diff --git a/.gitignore b/.gitignore index aeab61608..b77a59eab 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,9 @@ .DS_Store .DS_Store/* +# Test node modules +node_modules +node_modules/* +test/node_modules +test/node_modules/* +test/package-lock.json diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..78e2ed892 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,21 @@ +sudo: required +services: + - nodejs +language: php +node_js: + - "8" +before_install: + - mkdir ../js + - cp test/__config.js ../js/config.js + - touch ../authenticate.php + - which php +install: + - npm install + - npm install -g mocha +before_script: + - cd test + - node test_server.js & + - cd .. +script: + - mocha js/Helpers/test --recursive + - mocha test/functional_tests.js diff --git a/README.md b/README.md index 9100cddc0..1f5f81a8a 100644 --- a/README.md +++ b/README.md @@ -1,82 +1,45 @@ - -caMicroscope - A Web Based Annotation and Visualization Platform for Digitized Whole Slide Images +# caMicroscope +## A Web Based Annotation and Visualization Platform for Digitized Whole Slide Images -Ameen Kazerouni - -Ashish Sharma - -[Ganesh Iyer](http://ganeshiyer.net) - -Sanjay Agravat - -Shaohuan Li - -============ - -About -------- -GSOC Bio-medical Image Viewer Project is a HTML5 image viewer optimized for large bio-medical image data viewing. +#### Develop branch build status: +[![Build Status](https://travis-ci.org/camicroscope/caMicroscope.svg?branch=develop)](https://travis-ci.org/camicroscope/caMicroscope) -The Image Viewer server is based on the IIPImage server(http://iipimage.sourceforge.net/) which is an Fast CGI modeule written in C++ and IIPMooviewer-2.0(https://github.com/ruven/iipmooviewer) which is a HTML5 Ajax-based javascript image streaming client developed by Ruven. -This project forcuses on SVG annotation development, HTML5 canvas implementation and database design for viewing large Bio-Medical image data. +## About -Prerequisite --------- -The IIPImage server(http://iipimage.sourceforge.net/) will have to be installed in the server. +caMicroscope is a HTML5 image viewer optimized for large bio-medical image data viewing, with a strong emphasis on cancer pathology. -Apache or lighttpd web server will need to be installed as well. +The Image Viewer server is based on [IIPImage server](http://iipimage.sourceforge.net/) which is a Fast CGI module and [OpenSeaDragon](https://openseadragon.github.io/) which is a deep zoom image viewer. -PHP5 will be needed to handle the annotation saving function. -Features --------- +## Usage -*HTML5 Canvas Markup Drawing. Rectangle tool,ellipse tool, pencil tool, polyline tool, measurement tool and magnifying tool have been developed. +caMicroscope should be deployed as part of a stack; for further information see the [caMicroscope distribution repository](https://github.com/camicroscope/Distro). -*SVG Markup Displaying. The image markups are displayed as SVG(Scalable Vector Graphics) images which preserve good resolutions for different sizes of views +## Core Features -*Annotation/Markup data saving. The markups/annotations will be saved to the database using PHP scripts via Ajax calls. +* Variable resolution browser rendering of slide images of multiple formats -Specifications --------------- +* Segmentation analysis on user-selected regions -js/annotools.js is the main outcome of this project. It is an independent annotation module which allows users to draw markups/annotations on the image viewer.The annotation annotools object will need to be associated with a div tag id and a container id to run the tools smoothly. -An example would be like http://170.140.138.125/view.html. The annotools only work for HTML5 enabled browsers. +* Annotation drawing and sharing -css/annotools.css and the svg imges in the images folder are associated with the annotools.js. -js/iipmooviewer-2.0.js is the orignial IIPMooViewer with some customization. One big change is to add a displayAnnotation funciton in the requestImages function inside the IIPMooViewer class. Some small changes would be like the adjustment of the navigation window size. - -js/mootools-more.js and mootools-core.js would be the latest mootools framework. - -js/main.js is the image meta data handler. js/moreImages.js is the bottom slider which will display the image meta data more conveniently. - -api/annot.php is for saving and getting annotation meta. -api/annot.txt is the file storing the annotation data. This file has to be set as readable/writable to the public. - -api/image.php is the php script to get the image information from the database -api/annotation.php is the PHP script to get the annotation info from the database -api/state.php is to save the state of the viewer. The developers would be using zoomTo(zoom) and moveTo(left,top) to navigate to the saved state. - -view.html is for annotation saving without connecting to the database.You may test it here:http://170.140.138.125/view.html - -index.html and viewer.html is for the image viewer which is connected to the database. You may test it here.http://170.140.138.125 +## Contributors +Ameen Kazerouni -schema.sql is the database schema +Alina Jasniewski -Database Module ---------------- +Ashish Sharma -One approach for saving annotations is to use databases. As the annotations will be associated with a particular image, the annotations will have to contain one foreign key referencing the image id. +Feiqiao "Bridge" Wang +[Ganesh Iyer](http://ganeshiyer.net) -Image MetaData Viewing Module ------------------------------ +[Ryan Birmingham](http://rbirm.us) -The metadata is displayed as unsorted list on the bottom of the image viewer. This utilizes the tween function in Mootools. One example can be shown in viewer.html +Sanjay Agravat -Image Uploading Module ------------------------------ -This is handled by uploader.html and uploader.php. The images will by default be saved to the /usr/share/iip folder. +Shaohuan Li +Tammy DiPrima diff --git a/api/Configuration/config.php b/api/Configuration/config.php index 171b76ab8..9d71dc1b1 100644 --- a/api/Configuration/config.php +++ b/api/Configuration/config.php @@ -1,10 +1,28 @@ 'quip-data:9099', + 'kueHost' => 'quip-jobs:3000']; +} + + +$baseUrl = "http://" . $config['dataHost']; +$kueUrl = "http://" . $config['kueHost']; $serviceUrl = "$baseUrl/services/Camicroscope_DataLoader"; $annotationsUrl = "$baseUrl/services/Camicroscope_Annotations"; + +if (isset($_SESSION['db_name']) && !empty($_SESSION['db_name'])) { + + if ($_SESSION["db_name"] == "quip_comp"){ + $serviceUrl = "$baseUrl/services/Camicroscope_DataLoader_comp"; + $annotationsUrl = "$baseUrl/services/Camicroscope_Annotations_comp"; + } +} + $u24_userUrl = "$baseUrl/services/u24_user"; $imageUrl = "$serviceUrl/DataLoader"; $lymphocyteUrl = "$baseUrl/services/Camicroscope_Lymphocyte"; @@ -28,6 +46,7 @@ /* * temp */ + 'getOverlayTiles' => "$baseUrl/services/TileOverlay/Tiles/query/getTileLocation?", 'algorithmsForImage' => "$annotationsUrl/MarkupsForImages/query/MarkupsAvilableForImage?", 'getMultipleAnnotations' => "$annotationsUrl/MarkupLoader/query/getMultipleMarkups?", 'getROI' => "$annotationsUrl/MarkupLoader/query/getROI", //Featurescape URL. @@ -53,6 +72,8 @@ 'postDataForLymphocytes' => "$lymphocyteUrl/DataForLymphocytes/submit/json?", 'getLymphocyteData' => "$lymphocyteUrl/DataForLymphocytes/query/getLymphocytes?", 'getLymphocyteDataByCaseId' => "$lymphocyteUrl/DataForLymphocytes/query/getLymphocytesByCaseId?", + 'postDataForHeatmap' => "$lymphocyteUrl/HeatmapData/submit/json?", + 'getHeatmapData' => "$lymphocyteUrl/HeatmapData/query/getQualHeatmapByCaseidExecid?", /* Lymphocyte Superusers */ 'postSuperuserForLymphocytes' => "$lymphocyteUrl/LymphocyteUsers/submit/json?", @@ -77,26 +98,35 @@ /* Template */ 'retrieveTemplate' => "$templateUrl/AnnotationTemplate/query/retrieveTemplate", - 'retrieveTemplateClone' => "$templateUrl/AnnotationTemplate/query/retrieveTemplateClone", + 'retrieveTemplateByName' => "$templateUrl/AnnotationTemplate/query/retrieveTemplateByName", /* u24_user */ 'findUserByName' => "$u24_userUrl/user_data/query/findUserByName?", 'findUserByEmail' => "$u24_userUrl/user_data/query/findUserByEmail?", + 'findUser' => "$u24_userUrl/user_data/query/findUser?", 'findAdmin' => "$u24_userUrl/user_data/query/findAdmin?", 'findAllBindaasUsers'=>"$u24_userUrl/user_data/query/findAllBindaasUsers?", + 'findSuperUserCount'=>"$u24_userUrl/user_data/query/findSuperUserCount?", + 'deleteUserByName' => "$u24_userUrl/user_data/delete/deleteUserByName?", 'deleteUserByEmail'=> "$u24_userUrl/user_data/delete/deleteUserByEmail?", 'postUser' => "$u24_userUrl/user_data/submit/json", + 'setUserType' => "$u24_userUrl/user_data/delete/setUserType?", /* Image */ 'getDimensions' => "$imageUrl/query/getDimensionsByIID?api_key=", 'getFileLocation' => "$imageUrl/query/getFileLocationByIID?api_key=", + //'getTileLocation' => "$imageUrl/query/getTileLocationByIID?api_key=", 'getMPP' => "$imageUrl/query/getMPPByIID?api_key=", 'getImageInfoByCaseID'=> "$imageUrl/query/getImageInfoByCaseID?api_key=", - 'fastcgi_server' => "../fcgi-bin/iipsrv.fcgi", + 'fastcgi_server' => "/fcgi-bin/iipsrv.fcgi", + 'imageStatusUpdate'=> "$imageUrl/delete/imageStatusUpdate?", + 'getImageStatus'=> "$imageUrl/query/getImageStatusByCaseID?api_key=", + 'getImageAssignTo'=> "$imageUrl/query/getImageAssignToByCaseID?api_key=", + 'imageAssignTo'=> "$imageUrl/delete/imageAssignTo?", - /* Dynamic Services */ + /* Dynamic Services */ 'postWorkOrder' => "$dynamicServices/WorkOrders/submit/json", 'kueUrl' => $kueUrl ); diff --git a/api/Data/CamicUtils.php b/api/Data/CamicUtils.php index 05d997512..a9f3de83f 100644 --- a/api/Data/CamicUtils.php +++ b/api/Data/CamicUtils.php @@ -1,40 +1,64 @@ CONFIG = require '../Configuration/config.php'; - $this->api_key = $Session['api_key']; - } + public $CONFIG; + public $api_key; + + function __construct($Session) + { + include_once("RestRequest.php"); + $this->CONFIG = require '../Configuration/config.php'; + $this->api_key = trim($Session['api_key']); + } + + function getImageDimensions($tissueId) + { + $dimensionsUrl = $this->CONFIG['getDimensions'] . $this->api_key . "&TCGAId=" . $tissueId; + $getDimensionRequest = new RestRequest($dimensionsUrl, 'GET'); + $getDimensionRequest->execute(); + $dimensionList = json_decode($getDimensionRequest->responseBody); + $finalDimensions; - function getImageDimensions($tissueId) + foreach ($dimensionList as $singleDimension) { + $finalDimensions = $singleDimension; + break; + } + return $finalDimensions; + } + + function retrieveImageLocation($tissueId) + { + $fileUrl = $this->CONFIG['getFileLocation'] . $this->api_key . "&TCGAId=" . $tissueId; + $fileUrl = str_replace(" ", "%20", $fileUrl); + $getFileLocationRequest = new RestRequest($fileUrl, 'GET'); + $getFileLocationRequest->execute(); + $location = json_decode($getFileLocationRequest->responseBody); + return $location; + } + + function retrieveImageStatus($tissueId) { - $dimensionsUrl = $this->CONFIG['getDimensions'] . $this->api_key . "&TCGAId=" . $tissueId; - $getDimensionRequest = new RestRequest($dimensionsUrl, 'GET'); - $getDimensionRequest->execute(); - $dimensionList = json_decode($getDimensionRequest->responseBody); - $finalDimensions; - foreach($dimensionList as $singleDimension) - { - $finalDimensions = $singleDimension; - break; - } - return $finalDimensions; + $statusUrl = $this->CONFIG['getImageStatus'] . $this->api_key . "&TCGAId=" . $tissueId; + $statusUrl = str_replace(" ","%20",$statusUrl); + $getImageStatusRequest = new RestRequest($statusUrl,'GET'); + $getImageStatusRequest->execute(); + $status = json_decode($getImageStatusRequest->responseBody); + return $status; } - function retrieveImageLocation($tissueId) + + function retrieveImageAssignTo($tissueId) { - $fileUrl = $this->CONFIG['getFileLocation'] . $this->api_key . "&TCGAId=" . $tissueId; - $fileUrl = str_replace(" ","%20",$fileUrl); - $getFileLocationRequest = new RestRequest($fileUrl,'GET'); - $getFileLocationRequest->execute(); - $location = json_decode($getFileLocationRequest->responseBody); - return $location; + $statusUrl = $this->CONFIG['getImageAssignTo'] . $this->api_key . "&TCGAId=" . $tissueId; + //print_r($statusUrl); + $statusUrl = str_replace(" ","%20",$statusUrl); + $getImageAssignToRequest = new RestRequest($statusUrl,'GET'); + $getImageAssignToRequest->execute(); + $AssignTo = json_decode($getImageAssignToRequest->responseBody); + //print_r($AssignTo); + return $AssignTo; } - function retrieveMpp($tissueId) { $mppUrl = $this->CONFIG['getMPP'] . $this->api_key . "&TCGAId=" . $tissueId; @@ -49,46 +73,41 @@ function retrieveMpp($tissueId) break; } - return $finalMPP; - } + return $finalMPP; + } - function setUpSymLinks($fileLocation) - { - foreach($fileLocation[0] as $key => $value) - { - $path = "/tmp/symlinks/" . session_id(); - if(!is_dir($path)) - { - mkdir($path); - } - $file = strrchr($value, '/'); - $fileNameWithoutExtension = substr($file,0,-5); - if(is_dir($path . $fileNameWithoutExtension)) - { - $link = $path . $fileNameWithoutExtension . $file . ".dzi"; - } - - else - { - mkdir($path . $fileNameWithoutExtension); - $file = $path . $fileNameWithoutExtension . $file; - symlink($value, $file); - symlink($file, $file . ".dzi"); - $link = $file . ".dzi"; - } - } - - return $link; - } + function setUpSymLinks($fileLocation) + { + foreach ($fileLocation[0] as $key => $value) { + $path = "/tmp/symlinks/" . session_id(); + if (!is_dir($path)) { + mkdir($path); + } - function setUpSVSImage($fileLocation) - { - foreach($fileLocation[0] as $key => $value) - { - $link = str_replace("tiff","svs",$value); - $link = $link . ".dzi"; - } + $file = strrchr($value, '/'); + $fileNameWithoutExtension = substr($file, 0, -5); - return $link; - } + if (is_dir($path . $fileNameWithoutExtension)) { + $link = $path . $fileNameWithoutExtension . $file . ".dzi"; + } else { + mkdir($path . $fileNameWithoutExtension); + $file = $path . $fileNameWithoutExtension . $file; + symlink($value, $file); + symlink($file, $file . ".dzi"); + $link = $file . ".dzi"; + } + } + + return $link; + } + + function setUpSVSImage($fileLocation) + { + foreach ($fileLocation[0] as $key => $value) { + $link = str_replace("tiff", "svs", $value); + $link = $link . ".dzi"; + } + + return $link; + } } diff --git a/api/Data/deleteAnnotationWithinRectangle.php b/api/Data/deleteAnnotationWithinRectangle.php index 4d475c4b0..2106e9aa5 100644 --- a/api/Data/deleteAnnotationWithinRectangle.php +++ b/api/Data/deleteAnnotationWithinRectangle.php @@ -15,7 +15,7 @@ switch ($_SERVER['REQUEST_METHOD']) { case 'DELETE': - echo "PHP Deleteing"; + echo "PHP Deleting"; echo PHP_EOL; $case_id=$_GET["case_id"]; diff --git a/api/Data/deleteMarkups.php b/api/Data/deleteMarkups.php index 53ef960dd..839bdd041 100644 --- a/api/Data/deleteMarkups.php +++ b/api/Data/deleteMarkups.php @@ -14,7 +14,7 @@ switch ($_SERVER['REQUEST_METHOD']) { case 'DELETE': - echo "PHP Deleteing"; + echo "PHP Deleting"; $d = file_get_contents("php://input"); print_r($d); $data = []; diff --git a/api/Data/getAlgorithmsForImage.php b/api/Data/getAlgorithmsForImage.php index 540766e94..91167d3cc 100644 --- a/api/Data/getAlgorithmsForImage.php +++ b/api/Data/getAlgorithmsForImage.php @@ -21,7 +21,7 @@ $getRequest->execute(); - //Figure out how to parse reponse + //Figure out how to parse response $annotationList = ($getRequest->responseBody); if($annotationList) diff --git a/api/Data/getAnnotSpatial.php b/api/Data/getAnnotSpatial.php index ba7680013..48d9588d1 100644 --- a/api/Data/getAnnotSpatial.php +++ b/api/Data/getAnnotSpatial.php @@ -33,7 +33,7 @@ $getRequest->execute(); - //Figure out how to parse reponse + //Figure out how to parse response $annotationList = ($getRequest->responseBody); if($annotationList) diff --git a/api/Data/getAnnotSpatialFilter.php b/api/Data/getAnnotSpatialFilter.php index 150278bd6..035a6f169 100644 --- a/api/Data/getAnnotSpatialFilter.php +++ b/api/Data/getAnnotSpatialFilter.php @@ -28,7 +28,7 @@ $url = $getUrl . $iid ."&X1=" . $x . "&Y1=" . $y . "&X2=" . $x1 . "&Y2=" . $y1 . "&text.Author=" . $_GET["author"] . "&text.Grade=" . $_GET["grade"] . "&text.Multi=" . $_GET["multi"] . "&api_key=".$api_key; $getRequest = new RestRequest($url,'GET'); $getRequest->execute(); - //Figure out how to parse reponse + //Figure out how to parse response $annotationList = json_decode($getRequest->responseBody); if(json_encode($annotationList) == null) diff --git a/api/Data/getAnnotSpatialLymph.php b/api/Data/getAnnotSpatialLymph.php index 7cf384614..0176516d1 100644 --- a/api/Data/getAnnotSpatialLymph.php +++ b/api/Data/getAnnotSpatialLymph.php @@ -37,7 +37,7 @@ $getRequest->execute(); - //Figure out how to parse reponse + //Figure out how to parse response $annotationList = ($getRequest->responseBody); if($annotationList) diff --git a/api/Data/getAnnotSpatial_sc.php b/api/Data/getAnnotSpatial_sc.php index f8408348c..2eb8bd250 100644 --- a/api/Data/getAnnotSpatial_sc.php +++ b/api/Data/getAnnotSpatial_sc.php @@ -40,7 +40,7 @@ $getRequest->execute(); - //Figure out how to parse reponse + //Figure out how to parse response $annotationList = ($getRequest->responseBody); if($annotationList) diff --git a/api/Data/getImageInfoByCaseID.php b/api/Data/getImageInfoByCaseID.php index cb18cae07..841eb4131 100644 --- a/api/Data/getImageInfoByCaseID.php +++ b/api/Data/getImageInfoByCaseID.php @@ -26,7 +26,7 @@ $getRequest->execute(); - //Figure out how to parse reponse + //Figure out how to parse response $imageInfo = ($getRequest->responseBody); if($imageInfo) diff --git a/api/Data/getLymphocyteDataByCaseId.php b/api/Data/getLymphocyteDataByCaseId.php index bc7997cdc..9ee0598e0 100644 --- a/api/Data/getLymphocyteDataByCaseId.php +++ b/api/Data/getLymphocyteDataByCaseId.php @@ -20,7 +20,7 @@ $getRequest = new RestRequest($url,'GET'); $getRequest->execute(); - //Parse reponse + //Parse response $lymphocyteInfo = ($getRequest->responseBody); if($lymphocyteInfo) diff --git a/api/Data/getLymphocyteSuperusers.php b/api/Data/getLymphocyteSuperusers.php index 3f1961bca..3a9acd831 100644 --- a/api/Data/getLymphocyteSuperusers.php +++ b/api/Data/getLymphocyteSuperusers.php @@ -20,7 +20,7 @@ $getRequest = new RestRequest($url,'GET'); $getRequest->execute(); - //Parse reponse + //Parse response $lymphocyteSuperuserInfo = ($getRequest->responseBody); if($lymphocyteSuperuserInfo) diff --git a/api/Data/getMultipleAnnotationsNew.php b/api/Data/getMultipleAnnotationsNew.php index 6a8e04a3e..74a5bec5b 100644 --- a/api/Data/getMultipleAnnotationsNew.php +++ b/api/Data/getMultipleAnnotationsNew.php @@ -1,50 +1,55 @@ -execute(); - //print_r($url); - //print_r($getRequest); - //Figure out how to parse reponse - $annotationList = ($getRequest->responseBody); - - // print_r($annotationList); - if($annotationList) - echo ($annotationList); - else - echo "No annotations"; - - } + +if (isset($_GET["iid"])) { + $iid = $_GET["iid"]; + $x = $_GET["x"]; + if ($x < 0) + $x = 0.0; + $y = $_GET["y"]; + if ($y < 0) + $y = 0.0; + $x1 = $_GET["x1"]; + $y1 = $_GET["y1"]; + $area = $_GET["footprint"]; + + $algorithms_computer = urlencode($_GET["algorithms_computer"]); + $algorithms_human = urlencode($_GET["algorithms_human"]); + + $getUrl = $getUrl . "api_key=" . $api_key; + + $url = $getUrl . "&CaseId=" . $iid . "&x1=" . $x . "&y1=" . $y . "&x2=" . $x1 . "&y2=" . $y1 . "&footprint=" . $area . "&algorithms_computer=" . $algorithms_computer . "&algorithms_human=" . $algorithms_human; + + //echo $url; + $getRequest = new RestRequest($url, 'GET'); + $getRequest->execute(); + //print_r($url); + //print_r($getRequest); + //Figure out how to parse response + $annotationList = ($getRequest->responseBody); + + // print_r($annotationList); + if ($annotationList) + echo($annotationList); + else + echo "No annotations"; + +} ?> diff --git a/api/Data/getMultipleAnnots.php b/api/Data/getMultipleAnnots.php index 72cf768b3..105545b6b 100644 --- a/api/Data/getMultipleAnnots.php +++ b/api/Data/getMultipleAnnots.php @@ -39,7 +39,7 @@ //echo $output; $annotationList = $output; - //Figure out how to parse reponse + //Figure out how to parse response //$annotationList = ($getRequest->responseBody); if($annotationList) diff --git a/api/Data/getMultipleAnnotsClone.php b/api/Data/getMultipleAnnotsClone.php index d4182eb93..491c4483a 100644 --- a/api/Data/getMultipleAnnotsClone.php +++ b/api/Data/getMultipleAnnotsClone.php @@ -41,7 +41,7 @@ //print_r($url); //print_r($getRequest); - //Figure out how to parse reponse + //Figure out how to parse response $annotationList = ($getRequest->responseBody); // print_r($annotationList); diff --git a/api/Data/getMultipleAnnotsWithAttr.php b/api/Data/getMultipleAnnotsWithAttr.php index 90c73c1ad..4df042206 100644 --- a/api/Data/getMultipleAnnotsWithAttr.php +++ b/api/Data/getMultipleAnnotsWithAttr.php @@ -44,7 +44,7 @@ //echo $output; $annotationList = $output; - //Figure out how to parse reponse + //Figure out how to parse response //$annotationList = ($getRequest->responseBody); if($annotationList) diff --git a/api/Data/getOverlayTiles.php b/api/Data/getOverlayTiles.php new file mode 100644 index 000000000..ca3f43d7d --- /dev/null +++ b/api/Data/getOverlayTiles.php @@ -0,0 +1,37 @@ +execute(); + + // return value + $annotationList = ($getRequest->responseBody); + + if ($annotationList) + echo($annotationList); + else + echo "No annotations"; + +} diff --git a/api/Data/getProperties.php b/api/Data/getProperties.php new file mode 100644 index 000000000..052e1c6b5 --- /dev/null +++ b/api/Data/getProperties.php @@ -0,0 +1,110 @@ +execute(); + + + //Figure out how to parse reponse + $annotationList = json_decode($getRequest->responseBody); + //print_r($annotationList[0]['properties']); + + $annotationList[0]->properties->annotations->secret = "xxxx"; + //echo "\n---\n"; + + if($annotationList) + echo json_encode($annotationList); + else + echo "No annotations"; + } + break; + + case 'DELETE': + echo "PHP Deleteing"; + + + + $d = file_get_contents("php://input"); + print_r($d); + $data = []; + parse_str($d, $data); + //$data = json_decode($data); + //print_r($data); + + $id = $data['id']; + $secret = $data['secret']; + + + + + + //Check ID is human + $getUrl = $getUrl . "api_key=" . $api_key; + $url = $getUrl . "&id=" . $id; + //echo $url; + $getRequest = new RestRequest($url,'GET'); + $getRequest->execute(); + $annotationList = json_decode($getRequest->responseBody); + $annotation = $annotationList[0]; + $source = $annotation->provenance->analysis->source; + $annot_secret = $annotation->properties->annotations->secret; + if($source == "human"){ + if($secret == $annot_secret){ + echo "Source: ".$source; + + + $delUrl = $deleteUrl . "?api_key=".$api_key . "&id=".$id; + //echo $delUrl; + $curl = curl_init($delUrl); + + //Delete request + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE"); + curl_setopt($curl, CURLOPT_HEADER, false); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json',"OAuth-Token: $token")); + + // Make the REST call, returning the result + $response = curl_exec($curl); + print_r($response); + + echo "Deleted!"; + } else { + echo "Wrong secret"; + } + } else { + echo "Failed: Cant delete computer generated annotations"; + } + + + //Delete ID + + + break; +} + +?> diff --git a/api/Data/getPropertiesClone.php b/api/Data/getPropertiesClone.php index 94b0c33d0..cda2a0d76 100644 --- a/api/Data/getPropertiesClone.php +++ b/api/Data/getPropertiesClone.php @@ -31,7 +31,7 @@ $getRequest->execute(); - //Figure out how to parse reponse + //Figure out how to parse response $annotationList = json_decode($getRequest->responseBody); //print_r($annotationList[0]['properties']); diff --git a/api/Data/getROI.php b/api/Data/getROI.php index 4aeb7cd68..749bd26fa 100644 --- a/api/Data/getROI.php +++ b/api/Data/getROI.php @@ -28,7 +28,7 @@ $getRequest->execute(); - //Figure out how to parse reponse + //Figure out how to parse response $annotationList = json_decode($getRequest->responseBody); //print_r($annotationList[0]['properties']); diff --git a/api/Data/getUserByEmail.php b/api/Data/getUserByEmail.php new file mode 100644 index 000000000..30b7f39f8 --- /dev/null +++ b/api/Data/getUserByEmail.php @@ -0,0 +1,32 @@ +execute(); + $user = ($getRequest->responseBody); + if($user) + echo ($user); + else + echo "No user found."; + + break; +} +?> diff --git a/api/Data/heatmapData.php b/api/Data/heatmapData.php new file mode 100644 index 000000000..388e80ae0 --- /dev/null +++ b/api/Data/heatmapData.php @@ -0,0 +1,68 @@ +execute(); + + //Parse reponse + $heatmapInfo = ($getRequest->responseBody); + + if($heatmapInfo) + echo ($heatmapInfo); + else + echo "No heatmap data"; + + } + break; + + case 'POST': + //echo "Posting!!!"; + $heatmapInfo =$_POST; + $url = $postUrl . "api_key=".$api_key; + + //print_r($lymphocyteHeatmapInfo); + //print_r(json_encode($lymphocyteHeatmapInfo), JSON_NUMERIC_CHECK); + echo "posting data\n"; + echo $url; + $ch = curl_init(); + $headers= array('Accept: application/json','Content-Type: application/json'); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); + + curl_setopt($ch, CURLOPT_POSTFIELDS,json_encode($heatmapInfo, JSON_NUMERIC_CHECK)); + $result = curl_exec($ch); + if($result === false){ + $result = curl_error($ch); + } + curl_close($ch); + + echo $result; + + echo "done"; + break; +} +?> diff --git a/api/Data/imageStatusUpdate.php b/api/Data/imageStatusUpdate.php new file mode 100644 index 000000000..6e677499a --- /dev/null +++ b/api/Data/imageStatusUpdate.php @@ -0,0 +1,45 @@ + diff --git a/api/Data/loadState.php b/api/Data/loadState.php index 0e1831544..b090142b5 100644 --- a/api/Data/loadState.php +++ b/api/Data/loadState.php @@ -25,7 +25,7 @@ echo $url; $getRequest = new RestRequest($url,'GET'); $getRequest->execute(); - //Figure out how to parse reponse + //Figure out how to parse response $state = json_decode($getRequest->responseBody); if(json_encode($state) == null) diff --git a/api/Data/lymphocyteData.php b/api/Data/lymphocyteData.php index c329fba29..d7467b4d6 100644 --- a/api/Data/lymphocyteData.php +++ b/api/Data/lymphocyteData.php @@ -27,7 +27,7 @@ $getRequest = new RestRequest($url,'GET'); $getRequest->execute(); - //Parse reponse + //Parse response $lymphocyteHeatmapInfo = ($getRequest->responseBody); if($lymphocyteHeatmapInfo) diff --git a/api/Data/lymphocyteSuperusers.php b/api/Data/lymphocyteSuperusers.php index 2834fe803..62824fd10 100644 --- a/api/Data/lymphocyteSuperusers.php +++ b/api/Data/lymphocyteSuperusers.php @@ -26,7 +26,7 @@ $getRequest = new RestRequest($url,'GET'); $getRequest->execute(); - //Parse reponse + //Parse response $lymphocyteSuperuserInfo = ($getRequest->responseBody); if($lymphocyteSuperuserInfo) { diff --git a/api/Data/osdMetadataRetriever.php b/api/Data/osdMetadataRetriever.php index eed4ff8b2..5f5c24444 100644 --- a/api/Data/osdMetadataRetriever.php +++ b/api/Data/osdMetadataRetriever.php @@ -4,11 +4,17 @@ $utils = new CamicUtils($_SESSION); $tissueId = $_GET['imageId']; + $fileLocation = $utils->retrieveImageLocation($tissueId); +$imageStatus = $utils->retrieveImageStatus($tissueId); +$assignTo = $utils->retrieveImageAssignTo($tissueId); #$dzi = $utils->setUpSymLinks($fileLocation); $dzi = $utils->setUpSVSImage($fileLocation); $finalMpp = $utils->retrieveMpp($tissueId); + + $returnArray = array(); -array_push($returnArray,$finalMpp,$dzi); +array_push($returnArray,$finalMpp,$dzi,$imageStatus,$assignTo); echo json_encode($returnArray); + ?> diff --git a/api/Data/retreiveTemplate.php b/api/Data/retreiveTemplate.php deleted file mode 100644 index 6cfb21dee..000000000 --- a/api/Data/retreiveTemplate.php +++ /dev/null @@ -1,21 +0,0 @@ -execute(); -echo json_encode($templateRequest->responseBody); -?> - diff --git a/api/Data/retrieveTemplate.php b/api/Data/retrieveTemplate.php old mode 100644 new mode 100755 index 6cfb21dee..a8bc3d861 --- a/api/Data/retrieveTemplate.php +++ b/api/Data/retrieveTemplate.php @@ -12,10 +12,19 @@ $api_key = $_SESSION['api_key']; -$url = $templateUrl . "?api_key=$api_key"; +if (!isset($_GET) || empty($_GET["app_name"])) +{ + $url = $templateUrl . "?api_key=$api_key"; +} +else { + $app_name=$_GET["app_name"]; + $url = $templateUrl . "?api_key=$api_key" . "&app_name=$app_name"; +} + //echo $url; $templateRequest = new RestRequest($url,'GET'); $templateRequest->execute(); echo json_encode($templateRequest->responseBody); + ?> diff --git a/api/Data/retrieveTemplateClone.php b/api/Data/retrieveTemplateClone.php deleted file mode 100644 index 154f184f9..000000000 --- a/api/Data/retrieveTemplateClone.php +++ /dev/null @@ -1,21 +0,0 @@ -execute(); -echo json_encode($templateRequest->responseBody); -?> - diff --git a/css/csv2Json.css b/archive/csv2Json.css similarity index 100% rename from css/csv2Json.css rename to archive/csv2Json.css diff --git a/csv2Json.html b/archive/csv2Json.html similarity index 100% rename from csv2Json.html rename to archive/csv2Json.html diff --git a/api/Data/getAnnotNoSpatial.php b/archive/getAnnotNoSpatial.php similarity index 97% rename from api/Data/getAnnotNoSpatial.php rename to archive/getAnnotNoSpatial.php index 32f31de0f..760206d94 100644 --- a/api/Data/getAnnotNoSpatial.php +++ b/archive/getAnnotNoSpatial.php @@ -20,7 +20,7 @@ $url = $getUrl . $iid . "&username=" . $_SESSION['username'] . "&api_key=".$api_key; $getRequest = new RestRequest($url,'GET'); $getRequest->execute(); - //Figure out how to parse reponse + //Figure out how to parse response $annotationList = json_decode($getRequest->responseBody); if(json_encode($annotationList) == null) diff --git a/api/Data/getU24UserByEmail.php b/archive/getU24UserByEmail.php similarity index 94% rename from api/Data/getU24UserByEmail.php rename to archive/getU24UserByEmail.php index 2f7659608..45a42647f 100644 --- a/api/Data/getU24UserByEmail.php +++ b/archive/getU24UserByEmail.php @@ -35,7 +35,7 @@ $getRequest = new RestRequest($url,'GET'); $getRequest->execute(); - //Figure out how to parse reponse + //Figure out how to parse response $u24_user = json_decode($getRequest->responseBody); if($u24_user) diff --git a/index.php b/archive/index.php similarity index 100% rename from index.php rename to archive/index.php diff --git a/js/annotationtools/mooAnnotationTools.js b/archive/mooAnnotationTools.js similarity index 100% rename from js/annotationtools/mooAnnotationTools.js rename to archive/mooAnnotationTools.js diff --git a/mooCamicroscope.php b/archive/mooCamicroscope.php similarity index 100% rename from mooCamicroscope.php rename to archive/mooCamicroscope.php diff --git a/js/imagemetadatatools/mooImageMetadata.js b/archive/mooImageMetadata.js similarity index 100% rename from js/imagemetadatatools/mooImageMetadata.js rename to archive/mooImageMetadata.js diff --git a/api/Data/mooMetadataRetriever.php b/archive/mooMetadataRetriever.php similarity index 100% rename from api/Data/mooMetadataRetriever.php rename to archive/mooMetadataRetriever.php diff --git a/js/annotationtools/osdWordk.js b/archive/osdWordk.js similarity index 100% rename from js/annotationtools/osdWordk.js rename to archive/osdWordk.js diff --git a/queryBrowser.html b/archive/queryBrowser.html similarity index 100% rename from queryBrowser.html rename to archive/queryBrowser.html diff --git a/api/Data/retreiveClinicalData.php b/archive/retreiveClinicalData.php similarity index 100% rename from api/Data/retreiveClinicalData.php rename to archive/retreiveClinicalData.php diff --git a/api/Data/submitJobParameters.php b/archive/submitJobParameters.php similarity index 100% rename from api/Data/submitJobParameters.php rename to archive/submitJobParameters.php diff --git a/taskList.php b/archive/taskList.php similarity index 100% rename from taskList.php rename to archive/taskList.php diff --git a/temp b/archive/temp similarity index 100% rename from temp rename to archive/temp diff --git a/css/annotools.css b/css/annotools.css index 813cbf576..c09c10bf0 100644 --- a/css/annotools.css +++ b/css/annotools.css @@ -152,6 +152,15 @@ vertical-align: middle; font-family: Roboto-Light; } +.statusButton +{ + position: absolute; + left: 75%; + top: 12px; + font-size: 16px; + vertical-align: middle; + font-family: Roboto; +} .iidButton { position: absolute; @@ -310,10 +319,12 @@ #panelBody input{ color: #000; } -#panael .btn2{ - //background: #244B71; - +/* +#panel .btn2 { + background: #244B71; } +*/ + #panel .btn{ background: #244B71; color: #fff; @@ -339,7 +350,7 @@ z-index: 900999; background: #1976D2; box-shadow:1px 1px 1px 1px #555; - //padding: 15px; + /* padding: 15px; */ border-radius: 4px; color: #fff; opacity: 0.9; @@ -388,19 +399,19 @@ display: inline-block; } .wdzt-cell-layout input{ - //margin-left: 20px; + /* margin-left: 20px; */ width: 110px; margin-top: 5px; display: inline-block; } .wdzt-cell-layout input[type=number]{ - //margin-left: 20px; + /* margin-left: 20px; */ width: 38px; margin: 0; } .wdzt-cell-layout input[type=range]::-webkit-slider-runnable-track { - //margin-left: 20px; + /* margin-left: 20px; */ width:50px; width: 14px; } @@ -419,6 +430,7 @@ left: 120px; background: #244B71; } +/* #bookmarkURLDiv input{ color: #333; width: 100%; @@ -436,8 +448,9 @@ -webkit-box-shadow: 0px 0px 5px 2px #000000; -moz-box-shadow: 0px 0px 5px 2px #000000; box-shadow: 0px 0px 5px 2px #000000; - + } +*/ .checkbox input[type=checkbox], .checkbox-inline input[type=checkbox], .radio input[type=radio], .radio-inline input[type=radio]{ margin: 0; @@ -446,7 +459,7 @@ width: 10px; height: 10px; -// background: red; + /* background: red; */ position: relative; display: inline-block; top: 2px; @@ -467,5 +480,5 @@ #panelBody input[type="checkbox"] { float: left; display:inline-block; - //margin-top: -15px; + /* margin-top: -15px; */ } diff --git a/css/multiheattools.css b/css/multiheattools.css index b21e09323..8addf9653 100644 --- a/css/multiheattools.css +++ b/css/multiheattools.css @@ -38,6 +38,32 @@ } + +#qualitypanel { + width: 350px; + font-family: Arial, Roboto; + font-size: 12px; + height: 200px; + top: 60px; + left: 0; + position: fixed; + z-index: 900999; + background: #1976D2; + box-shadow:1px 1px 1px 1px #555; + padding: 10px; + border-radius: 10px; + color: #fff; + opacity: 0.9; +} + +#qualitypanel, input.tb { + color: #000; +} +#qslider { + margin: 50px; + width:70%; +} + #markuppanel { width: 220px; font-family: Arial, Roboto; @@ -56,6 +82,25 @@ } + +#qualitymarkuppanel { + width: 220px; + font-family: Arial, Roboto; + font-size: 12px; + height: 270px; + top: 60px; + left: 0; + position: fixed; + z-index: 900999; + background: #1976D2; + box-shadow:1px 1px 1px 1px #555; + padding: 10px; + border-radius: 10px; + color: #fff; + opacity: 0.9; + +} + #switchuserpanel { width: 235px; font-family: Arial, Roboto; @@ -85,6 +130,7 @@ position:relative; top:10px; left:120px; + color: #fff; text-align:right; background-color: #008CBA; border: none; @@ -115,6 +161,16 @@ background-color: crimson; } +#closeQualityPanel { + display: inline-block; + width: 16px; + float:right; +} + +#closeQualityPanel:hover { + background-color: crimson; +} + #closeMarkupPanel { display: inline-block; width: 16px; @@ -125,6 +181,16 @@ background-color: crimson; } +#closeQualityMarkupPanel { + display: inline-block; + width: 16px; + float:right; +} + +#closeQualityMarkupPanel:hover { + background-color: crimson; +} + #closeSwitchUser { display: inline-block; width: 16px; diff --git a/css/nouislider.css b/css/nouislider.css new file mode 100644 index 000000000..b489fe43b --- /dev/null +++ b/css/nouislider.css @@ -0,0 +1,260 @@ +/*! nouislider - 10.0.0 - 2017-05-28 14:52:48 */ +/* Functional styling; + * These styles are required for noUiSlider to function. + * You don't need to change these rules to apply your design. + */ +.noUi-target, +.noUi-target * { + -webkit-touch-callout: none; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + -webkit-user-select: none; + -ms-touch-action: none; + touch-action: none; + -ms-user-select: none; + -moz-user-select: none; + user-select: none; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.noUi-target { + position: relative; + direction: ltr; +} +.noUi-base { + width: 100%; + height: 100%; + position: relative; + z-index: 1; + /* Fix 401 */ +} +.noUi-connect { + position: absolute; + right: 0; + top: 0; + left: 0; + bottom: 0; +} +.noUi-origin { + position: absolute; + height: 0; + width: 0; +} +.noUi-handle { + position: relative; + z-index: 1; +} +.noUi-state-tap .noUi-connect, +.noUi-state-tap .noUi-origin { + -webkit-transition: top 0.3s, right 0.3s, bottom 0.3s, left 0.3s; + transition: top 0.3s, right 0.3s, bottom 0.3s, left 0.3s; +} +.noUi-state-drag * { + cursor: inherit !important; +} +/* Painting and performance; + * Browsers can paint handles in their own layer. + */ +.noUi-base, +.noUi-handle { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +/* Slider size and handle placement; + */ +.noUi-horizontal { + height: 18px; +} +.noUi-horizontal .noUi-handle { + width: 34px; + height: 28px; + left: -17px; + top: -6px; +} +.noUi-vertical { + width: 18px; +} +.noUi-vertical .noUi-handle { + width: 28px; + height: 34px; + left: -6px; + top: -17px; +} +/* Styling; + */ +.noUi-target { + background: #FAFAFA; + border-radius: 4px; + border: 1px solid #D3D3D3; + box-shadow: inset 0 1px 1px #F0F0F0, 0 3px 6px -5px #BBB; +} +.noUi-connect { + background: #3FB8AF; + border-radius: 4px; + box-shadow: inset 0 0 3px rgba(51, 51, 51, 0.45); + -webkit-transition: background 450ms; + transition: background 450ms; +} +/* Handles and cursors; + */ +.noUi-draggable { + cursor: ew-resize; +} +.noUi-vertical .noUi-draggable { + cursor: ns-resize; +} +.noUi-handle { + border: 1px solid #D9D9D9; + border-radius: 3px; + background: #FFF; + cursor: default; + box-shadow: inset 0 0 1px #FFF, inset 0 1px 7px #EBEBEB, 0 3px 6px -3px #BBB; +} +.noUi-active { + box-shadow: inset 0 0 1px #FFF, inset 0 1px 7px #DDD, 0 3px 6px -3px #BBB; +} +/* Handle stripes; + */ +.noUi-handle:before, +.noUi-handle:after { + content: ""; + display: block; + position: absolute; + height: 14px; + width: 1px; + background: #E8E7E6; + left: 14px; + top: 6px; +} +.noUi-handle:after { + left: 17px; +} +.noUi-vertical .noUi-handle:before, +.noUi-vertical .noUi-handle:after { + width: 14px; + height: 1px; + left: 6px; + top: 14px; +} +.noUi-vertical .noUi-handle:after { + top: 17px; +} +/* Disabled state; + */ +[disabled] .noUi-connect { + background: #B8B8B8; +} +[disabled].noUi-target, +[disabled].noUi-handle, +[disabled] .noUi-handle { + cursor: not-allowed; +} +/* Base; + * + */ +.noUi-pips, +.noUi-pips * { + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.noUi-pips { + position: absolute; + color: #999; +} +/* Values; + * + */ +.noUi-value { + position: absolute; + white-space: nowrap; + text-align: center; +} +.noUi-value-sub { + color: #ccc; + font-size: 8px; +} +/* Markings; + * + */ +.noUi-marker { + position: absolute; + background: #CCC; +} +.noUi-marker-sub { + background: #AAA; +} +.noUi-marker-large { + background: #AAA; +} +/* Horizontal layout; + * + */ +.noUi-pips-horizontal { + padding: 10px 0; + height: 80px; + top: 100%; + left: 0; + width: 100%; +} +.noUi-value-horizontal { + -webkit-transform: translate3d(-50%, 50%, 0); + transform: translate3d(-50%, 50%, 0); +} +.noUi-marker-horizontal.noUi-marker { + margin-left: -1px; + width: 2px; + height: 5px; +} +.noUi-marker-horizontal.noUi-marker-sub { + height: 5px; +} +.noUi-marker-horizontal.noUi-marker-large { + height: 7px; +} +/* Vertical layout; + * + */ +.noUi-pips-vertical { + padding: 0 10px; + height: 100%; + top: 0; + left: 100%; +} +.noUi-value-vertical { + -webkit-transform: translate3d(0, 50%, 0); + transform: translate3d(0, 50%, 0); + padding-left: 25px; +} +.noUi-marker-vertical.noUi-marker { + width: 5px; + height: 2px; + margin-top: -1px; +} +.noUi-marker-vertical.noUi-marker-sub { + width: 10px; +} +.noUi-marker-vertical.noUi-marker-large { + width: 15px; +} +.noUi-tooltip { + display: block; + position: absolute; + border: 1px solid #D9D9D9; + border-radius: 3px; + background: #fff; + color: #000; + padding: 5px; + text-align: center; + white-space: nowrap; +} +.noUi-horizontal .noUi-tooltip { + -webkit-transform: translate(-50%, 0); + transform: translate(-50%, 0); + left: 50%; + bottom: 120%; +} +.noUi-vertical .noUi-tooltip { + -webkit-transform: translate(0, -50%); + transform: translate(0, -50%); + top: 50%; + right: 120%; +} diff --git a/css/nouislider.min.css b/css/nouislider.min.css new file mode 100644 index 000000000..fc1a3b39d --- /dev/null +++ b/css/nouislider.min.css @@ -0,0 +1 @@ +/*! nouislider - 10.0.0 - 2017-05-28 14:52:48 */.noUi-target,.noUi-target *{-webkit-touch-callout:none;-webkit-tap-highlight-color:transparent;-webkit-user-select:none;-ms-touch-action:none;touch-action:none;-ms-user-select:none;-moz-user-select:none;user-select:none;-moz-box-sizing:border-box;box-sizing:border-box}.noUi-target{position:relative;direction:ltr}.noUi-base{width:100%;height:100%;position:relative;z-index:1}.noUi-connect{position:absolute;right:0;top:0;left:0;bottom:0}.noUi-origin{position:absolute;height:0;width:0}.noUi-handle{position:relative;z-index:1}.noUi-state-tap .noUi-connect,.noUi-state-tap .noUi-origin{-webkit-transition:top .3s,right .3s,bottom .3s,left .3s;transition:top .3s,right .3s,bottom .3s,left .3s}.noUi-state-drag *{cursor:inherit!important}.noUi-base,.noUi-handle{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.noUi-horizontal{height:18px}.noUi-horizontal .noUi-handle{width:34px;height:28px;left:-17px;top:-6px}.noUi-vertical{width:18px}.noUi-vertical .noUi-handle{width:28px;height:34px;left:-6px;top:-17px}.noUi-target{background:#FAFAFA;border-radius:4px;border:1px solid #D3D3D3;box-shadow:inset 0 1px 1px #F0F0F0,0 3px 6px -5px #BBB}.noUi-connect{background:#3FB8AF;border-radius:4px;box-shadow:inset 0 0 3px rgba(51,51,51,.45);-webkit-transition:background 450ms;transition:background 450ms}.noUi-draggable{cursor:ew-resize}.noUi-vertical .noUi-draggable{cursor:ns-resize}.noUi-handle{border:1px solid #D9D9D9;border-radius:3px;background:#FFF;cursor:default;box-shadow:inset 0 0 1px #FFF,inset 0 1px 7px #EBEBEB,0 3px 6px -3px #BBB}.noUi-active{box-shadow:inset 0 0 1px #FFF,inset 0 1px 7px #DDD,0 3px 6px -3px #BBB}.noUi-handle:after,.noUi-handle:before{content:"";display:block;position:absolute;height:14px;width:1px;background:#E8E7E6;left:14px;top:6px}.noUi-handle:after{left:17px}.noUi-vertical .noUi-handle:after,.noUi-vertical .noUi-handle:before{width:14px;height:1px;left:6px;top:14px}.noUi-vertical .noUi-handle:after{top:17px}[disabled] .noUi-connect{background:#B8B8B8}[disabled] .noUi-handle,[disabled].noUi-handle,[disabled].noUi-target{cursor:not-allowed}.noUi-pips,.noUi-pips *{-moz-box-sizing:border-box;box-sizing:border-box}.noUi-pips{position:absolute;color:#999}.noUi-value{position:absolute;white-space:nowrap;text-align:center}.noUi-value-sub{color:#ccc;font-size:10px}.noUi-marker{position:absolute;background:#CCC}.noUi-marker-large,.noUi-marker-sub{background:#AAA}.noUi-pips-horizontal{padding:10px 0;height:80px;top:100%;left:0;width:100%}.noUi-value-horizontal{-webkit-transform:translate3d(-50%,50%,0);transform:translate3d(-50%,50%,0)}.noUi-marker-horizontal.noUi-marker{margin-left:-1px;width:2px;height:5px}.noUi-marker-horizontal.noUi-marker-sub{height:10px}.noUi-marker-horizontal.noUi-marker-large{height:15px}.noUi-pips-vertical{padding:0 10px;height:100%;top:0;left:100%}.noUi-value-vertical{-webkit-transform:translate3d(0,50%,0);transform:translate3d(0,50%,0);padding-left:25px}.noUi-marker-vertical.noUi-marker{width:5px;height:2px;margin-top:-1px}.noUi-marker-vertical.noUi-marker-sub{width:10px}.noUi-marker-vertical.noUi-marker-large{width:15px}.noUi-tooltip{display:block;position:absolute;border:1px solid #D9D9D9;border-radius:3px;background:#fff;color:#000;padding:5px;text-align:center;white-space:nowrap}.noUi-horizontal .noUi-tooltip{-webkit-transform:translate(-50%,0);transform:translate(-50%,0);left:50%;bottom:120%}.noUi-vertical .noUi-tooltip{-webkit-transform:translate(0,-50%);transform:translate(0,-50%);top:50%;right:120%} \ No newline at end of file diff --git a/customized/lymph/markup_types.json b/customized/lymph/markup_types.json new file mode 100644 index 000000000..0bc0b8b4c --- /dev/null +++ b/customized/lymph/markup_types.json @@ -0,0 +1,58 @@ +[ + { + "caption":"Vessel - Normal", + "JSName":"VesselNormal", + "DBName":"VesselNormal", + "color":"green", + "linewidth":"3", + "lineaffect":"1" + }, + { + "caption":"Vessel - Hyperplastic", + "JSName":"VesselHyperplastic", + "DBName":"VesselHyperplastic", + "color":"orange", + "linewidth":"3", + "lineaffect":"1" + }, + { + "caption":"Vessel - Proliferative", + "JSName":"VesselProliferative", + "DBName":"VesselProliferative", + "color":"red", + "linewidth":"3", + "lineaffect":"1" + }, + { + "caption":"NULL", + "JSName":"NULL", + "DBName":"NULL", + "color":"NULL", + "linewidth":"NULL", + "lineaffect":"NULL" + }, + { + "caption":"Tumor - Low", + "JSName":"TumorLow", + "DBName":"TumorLow", + "color":"green", + "linewidth":"3", + "lineaffect":"1" + }, + { + "caption":"Tumor - Med", + "JSName":"TumorMed", + "DBName":"TumorMed", + "color":"orange", + "linewidth":"3", + "lineaffect":"1" + }, + { + "caption":"Tumor - High", + "JSName":"TumorHigh", + "DBName":"TumorHigh", + "color":"red", + "linewidth":"3", + "lineaffect":"1" + } +] diff --git a/customized/lymph/testgit.txt b/customized/lymph/testgit.txt new file mode 100644 index 000000000..8baef1b4a --- /dev/null +++ b/customized/lymph/testgit.txt @@ -0,0 +1 @@ +abc diff --git a/images/SpyGlass.svg b/images/SpyGlass.svg new file mode 100644 index 000000000..fd15cac17 --- /dev/null +++ b/images/SpyGlass.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.6.2 2017-12-06 20:30:33 +0000iTunesArtworkSpy Glass diff --git a/images/cellseg.svg b/images/cellseg.svg new file mode 100644 index 000000000..183a1a3f5 --- /dev/null +++ b/images/cellseg.svg @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/lock_icon.png b/images/lock_icon.png new file mode 100644 index 000000000..cd8d658dc Binary files /dev/null and b/images/lock_icon.png differ diff --git a/images/share.svg b/images/share.svg new file mode 100644 index 000000000..e375f28ce --- /dev/null +++ b/images/share.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/spyglass_temp.png b/images/spyglass_temp.png new file mode 100644 index 000000000..38111e1a9 Binary files /dev/null and b/images/spyglass_temp.png differ diff --git a/images/unlock_icon.png b/images/unlock_icon.png new file mode 100644 index 000000000..f82f703d0 Binary files /dev/null and b/images/unlock_icon.png differ diff --git a/js/Helpers/ClientPrefManager.js b/js/Helpers/ClientPrefManager.js new file mode 100644 index 000000000..ab90c3463 --- /dev/null +++ b/js/Helpers/ClientPrefManager.js @@ -0,0 +1,73 @@ +// Work with a client database to store and get values +var ClientPrefManager = new Class({ + initialize: function (schema) { + this.schema = schema; + var indexedDB = window.indexedDB || window.webkitIndexedDB || window.msIndexedDB; + var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange; + var openCopy = indexedDB && indexedDB.open; + var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction; + if (IDBTransaction) + { + IDBTransaction.READ_WRITE = IDBTransaction.READ_WRITE || 'readwrite'; + IDBTransaction.READ_ONLY = IDBTransaction.READ_ONLY || 'readonly'; + } + var request = indexedDB.open(this.schema); + request.onupgradeneeded = function(e) + { + var idb = e.target.result; + if (!idb.objectStoreNames.contains(this.schema)) + { + var store = idb.createObjectStore(this.schema, {keyPath: 'pref'}); + } + } + }, + set_pref: function(pref, val){ + var request = indexedDB.open(this.schema); + + request.onsuccess = function(e) + { + var idb = e.target.result; + var trans = idb.transaction(this.schema, IDBTransaction.READ_WRITE); + var store = trans.objectStore(this.schema); + + var requestAdd = store.put({pref: pref, value: val}); + requestAdd.onsuccess = function(e) { + console.log(`Stored {pref: ${pref}, value: ${val}}`) + }; + + requestAdd.onfailure = function(e) { + console.log("There was some issue with storing the requested preference.") + }; + }; + }, + get_pref: function(pref, cb){ + var request = indexedDB.open(this.schema); + request.onsuccess = function(e) + { + idb = e.target.result; + var transaction = idb.transaction(this.schema, IDBTransaction.READ_ONLY); + var objectStore = transaction.objectStore(this.schema); + + var request = objectStore.get(pref) + request.onsuccess = function(event) + { + var data = event.target.result; + if (data) + { + console.log(`Found ${data.pref} = ${data.value}`); + cb(data.value); + } + else + { + console.log('No Entry Found.'); + cb(null); + } + }; + }; + } +}); + +// example of usage of this helper: +// var a = new ClientPrefManager("viewer"); +// a.set_pref("a","a"); +// a.get_pref("a", console.log) diff --git a/js/Helpers/SideSplit/MiniDraw.js b/js/Helpers/SideSplit/MiniDraw.js new file mode 100644 index 000000000..32a4d31b1 --- /dev/null +++ b/js/Helpers/SideSplit/MiniDraw.js @@ -0,0 +1,194 @@ +// need: +// ViewportCalibratedCanvas +// proxytools +// coordinateView (well, not really, but it'd be silly not to have) +// SideSplit +/////// +// utils +function objToParamStr(obj) { + var parts = []; + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + if (Array.isArray(obj[i])) { + // arrays are a list of strings with escaped quotes, surrounded by [] + parts.push(encodeURIComponent(i) + "=" + encodeURIComponent("[" + obj[i].map((x) => '\"' + x + '\"').toString() + "]")); + } else { + parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i])); + } + } + } + return parts.join("&"); +} + +function apiCall(callback, url, params) { + fetch(url + "?" + objToParamStr(params), { + credentials: "same-origin" + }) + .then((x) => x.json()) + .then(function(response) { + callback(response); + }) + .catch((x) => console.warn(x)); +} + +var stringToColor = function(str) { + var hash = 0; + for (var i = 0; i < str.length; i++) { + hash = str.charCodeAt(i) + ((hash << 5) - hash); + } + var colorlist = ['#1b9e77', '#d95f02', '#e7298a', '#66a61e', '#e6ab02', '#a6761d', '#666666']; + return colorlist[Math.abs(hash) % colorlist.length]; +} + +class annotStore { + /** + * Annotation API Interactions + * @param {string} id - the image id + * @param {object} [options] - optional substitution for api urls + */ + constructor(id, options) { + // image id + this.id = id; + // TODO cache?? + this.algDataUrl = options.algUrl || "api/Data/getMultipleAnnots.php"; + this.algListUrl = options.algListUrl || "api/Data/getAlgorithmsForImage.php"; + } + + /** + * Get a list of avaliable algorithms for the image + * @param {function} callback - callback for the result data + */ + getAlgList(callback) { + var params = { + "iid": this.id + } + apiCall(callback, this.algListUrl, params); + } + + /** + * Get a list of avaliable algorithms for the image + * @param {function} callback - callback for the result data + */ + getAlgData(x1, y1, x2, y2, footprint, algs, callback) { + // sanitization/validation + x1 = x1 < 0 ? 0 : x1; + y1 = y1 < 0 ? 0 : y1; + x2 = x2 < 0 ? 0 : x2; + y2 = y2 < 0 ? 0 : y2; + // set params object + var params = { + "iid": this.id, + "x": x1, + "x1": x2, + "y": y1, + "y1": y2, + "footprint": footprint, + "algorithms": algs + }; + apiCall(callback, this.algDataUrl, params); + } +} + + +function drawFromList(data, context) { + data.forEach(function(annotation) { + let id = annotation.provenance.analysis.execution_id; + let color = stringToColor(id); + let type = annotation.geometry.type; + let coords = annotation.geometry.coordinates[0]; + if (!type || type == "Polygon") { + context.strokeStyle = color; + let first = coords.splice(0, 1); + context.moveTo(first[0], first[1]); + context.beginPath(); + coords.forEach(function(coord) { + let x = coord[0]; + let y = coord[1]; + context.lineTo(x, y); + }); + context.stroke(); + // stop + } else { + console.warn("Don't know how to draw '" + type + "'"); + } + }) +} + +class annotations { + constructor(id, viewer, context, imagingHelper, options) { + this.id = id; + this.store = new annotStore(id, options); + this.viewer = viewer; + this.options = options; + this.selection = []; + this.context = context; + this.imagingHelper = imagingHelper; + this.lastBounds = [0, 0, 0, 0]; + this.lastZoom = 0; + } + + // draw using current viewer state + draw() { + // bounds for collision + let x = this.imagingHelper._viewportOrigin['x']; + let y = this.imagingHelper._viewportOrigin['y']; + let w = this.imagingHelper._viewportWidth; + let h = this.imagingHelper._viewportHeight; + + let z = this.viewer.viewport.getZoom(); + + // bounds for drawing + let x1 = x - w; + let y1 = y - h; + let x2 = x1 + 2 * (w); + let y2 = y1 + 2 * (h); + + // calculate footprint for api + var max = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(9), this.imagingHelper.physicalToDataY(9)); + var origin = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(0), this.imagingHelper.physicalToDataY(0)); + var footprint = (max.x - origin.x) * (max.y - origin.y); + + // is any part of current view out of last rectangle? + let panUpdate = x < this.lastBounds[0] || y < this.lastBounds[2] || x + w > this.lastBounds[1] || y + h > this.lastBounds[3]; + + // has zoom changed enough? + let zoomUpdate = (this.lastZoom / z) >= 2 || (this.lastZoom / z) <= 0.5; + if (panUpdate || zoomUpdate) { + // console.info("NEW: " + x + ", " + x + w + ", " + y + ", " + y + h, +", " + z) + // console.info("OLD: " + this.lastBounds + ", " + this.lastZoom); + this.context.__clear_queue(); + this.lastZoom = z; + this.lastBounds = [x1, x2, y1, y2]; + this.store.getAlgData(x1, y1, x2, y2, footprint, this.selection, (data) => drawFromList(data, this.context)); + + } + + + } + + // forcr a redraw from memory + forceDraw(){ + this.context.__clear_queue(); + // calculate footprint for api + var max = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(9), this.imagingHelper.physicalToDataY(9)); + var origin = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(0), this.imagingHelper.physicalToDataY(0)); + var footprint = (max.x - origin.x) * (max.y - origin.y); + this.store.getAlgData(this.lastBounds[0], this.lastBounds[2], this.lastBounds[1], this.lastBounds[3], footprint, this.selection, (data) => drawFromList(data, this.context)); + // not triggered by pan or zoom, so trigger osd to redraw too + this.viewer.viewport.panBy(new OpenSeadragon.Point(0.00001, 0.00001)); + } + + select(alg) { + if (this.selection.indexOf(alg) == -1) { + this.selection.push(alg); + } + } + + deselect(alg) { + let pos = this.selection.indexOf(alg) + if (pos > -1) { + this.selection.splice(pos, 1); + } + } + +} diff --git a/js/Helpers/SideSplit/ProxyTools.js b/js/Helpers/SideSplit/ProxyTools.js new file mode 100644 index 000000000..e9c478ac9 --- /dev/null +++ b/js/Helpers/SideSplit/ProxyTools.js @@ -0,0 +1,66 @@ +// call delayer to store then later apply +// {delayer obj}.__apply_all(new_base) applies everything done to the delayer obj to new base +function delayer(base){ + // add our delay functions/objects to base + base.__queue = []; + base.__apply_all = function(new_base){ + base.__queue.forEach(function(instruction){ + if (instruction[0]==="set"){ + new_base[instruction[1]] = instruction[2]; + } + else if (instruction[0]==="fcn"){ + if (typeof new_base[instruction[1]] === "function"){ + new_base[instruction[1]](...instruction[2]); + } + } + }) + } + var handler = { + get(obj, prop, val){ + // what if we're looking for queue or apply all? + if (prop === "__queue"){ + return obj.__queue; + } + if (prop === "__clear_queue"){ + return () => (obj.__queue = []); + } + else if (prop === "__apply_all"){ + return obj.__apply_all; + } else { + return function (...args){ + obj.__queue.push(["fcn", prop, args]); + } + } + }, + set(obj, prop, val) { + obj.__queue.push(["set", prop, val]); + } + } + return new Proxy(base, handler); +} + +// call cloner with base and a list of items to clone (same type preferably) of the same type +function cloner(clones){ + var handler = { + get(target, name, reciever){ + if (typeof clones[0][name] == "function"){ + // call the function with args to all contexts + return function (...args){ + var ret = clones[0][name](...args); + clones.slice(1).forEach((x) => (x[name](...args))); + // return whatever base returns + return ret; + } + } else { + // just return base context value if it's not a function + return clones[0][name]; + } + + }, + set(obj, prop, val) { + clones.forEach((x) => x[prop] = val);; + return val; + } + } + return new Proxy(clones, handler); +} diff --git a/js/Helpers/SideSplit/SideSplit.js b/js/Helpers/SideSplit/SideSplit.js new file mode 100644 index 000000000..99bd66386 --- /dev/null +++ b/js/Helpers/SideSplit/SideSplit.js @@ -0,0 +1,94 @@ +var rhs_viewer; + +function getAlgs(caseid, cb){ + fetch("api/Data/getAlgorithmsForImage.php?iid=" + caseid, { + credentials: "same-origin" + }) + .then((x)=>(x.json())) + .then((y)=>(cb(y))) +} + +// init +function init_sbs() { + + // div for right viewer + var rhs = document.createElement('div'); + rhs.style.position = "absolute"; + rhs.style.zIndex = "5"; + rhs.style.right = "0px"; + rhs.style.width = "50%"; + rhs.style.height = "700px" + rhs.style.display = "none"; + rhs.id = "right_sidebyside"; + document.body.appendChild(rhs); + + //hidden input for calibration + var calib = document.createElement('input'); + calib.type = "hidden" + calib.id = "sbs_calibration" + calib.value = "0,0" + document.body.appendChild(calib); + + //hidden input for activation + var activ = document.createElement('input'); + activ.type = "hidden" + activ.id = "sbs_activation" + activ.value = "active" + document.body.appendChild(activ); + + + var prefixurl = "https://cdn.jsdelivr.net/npm/openseadragon@2.3/build/openseadragon/images/"; + rhs_viewer = OpenSeadragon({ + id: "right_sidebyside", + prefixUrl: prefixurl, + showNavigationControl: false + }); + + window.setTimeout(coordinatedView(viewer, rhs_viewer), 500); + + // silly button fix attempt + rhs_viewer.buttons = viewer.buttons; +} + +function show_sbs() { + var rhs = document.getElementById("right_sidebyside"); + rhs.style.display = "block"; + var lhs = document.getElementById("viewer"); + lhs.style.width = "50%"; + lhs.style.left = "0px"; + viewer.viewport.zoomTo(2 * viewer.viewport.getZoom()); +} + +function unlock() { + document.getElementById("sbs_activation").value = "not" +} + +// re-lock with "previous" calibration +function snapLock() { + document.getElementById("sbs_activation").value = "active" +} + +// re-lock with "current" calibration +function freeLock() { + // get the differenct between the viewers, set as calib + var diff = rhs_viewer.viewport.getCenter(true).minus(viewer.viewport.getCenter(true)) + document.getElementById("sbs_calibration").value = [diff.x, diff.y].toString(); + document.getElementById("sbs_activation").value = "active" +} + +function hide_sbs() { + var rhs = document.getElementById("right_sidebyside"); + rhs.style.display = "none"; + var lhs = document.getElementById("viewer"); + lhs.style.width = "100%"; + lhs.style.left = "0px"; + viewer.viewport.zoomTo(0.5 * viewer.viewport.getZoom()); +} + + +init_sbs(); + +document.getElementById("right_sidebyside").style.height = window.innerHeight + "px" +window.onresize = function() { + document.getElementById("right_sidebyside").style.height = window.innerHeight + "px" +} diff --git a/js/Helpers/SideSplit/ViewportCalibratedCanvas.js b/js/Helpers/SideSplit/ViewportCalibratedCanvas.js new file mode 100644 index 000000000..6657db6f4 --- /dev/null +++ b/js/Helpers/SideSplit/ViewportCalibratedCanvas.js @@ -0,0 +1,137 @@ +function ViewportCalibratedCanvas(base, viewer) { + // translation methods + function convertPoint(x, y) { + var pt = new OpenSeadragon.Point(x, y); + return viewer.viewport.viewportToImageCoordinates(pt); + } + function convertLen(x, y) { + var pt = new OpenSeadragon.Point(x, y); + var pt_ref = new OpenSeadragon.Point(0, 0); + var im_pt = viewer.viewport.viewportToImageCoordinates(pt); + var im_pt_ref = viewer.viewport.viewportToImageCoordinates(pt_ref); + return im_pt.minus(im_pt_ref); + } + + var handler = { + get(obj, prop, val) { + // which points need to be converted for which method + // 1 and 2 are points, 3 and 4 are len (or not present) + var _pt2_len2 = ["clearRect", "fillRect", "strokeRect", "moveTo", "lineTo", "rect", "translate", "ellipse"]; + // all args are sets of points + var _allpoints = ["createLinearGradient", "createRadialGradient", "bezierCurveTo", "quadraticCurveTo", "drawImage", "getImageData"] + // transformation matrix + var _tramat = ["transform", "setTransform"] + // text x y + var _txt = ["fillText", "strokeText"] + if (_pt2_len2.indexOf(prop) >= 0) { + return function(...args) { + if (args.length >= 2) { + var pt = convertPoint(args[0], args[1]) + args[0] = pt.x; + args[1] = pt.y; + } + if (args.length >= 4) { + var pt = convertLen(args[2], args[3]) + args[2] = pt.x; + args[3] = pt.y; + } + obj[prop](...args); + } + } else if (_allpoints.indexOf(prop) >= 0) { + return function(...args) { + // for each set of two, convert + for (var i = 0; i < Math.floor(args.length / 2); i++) { + var pt = convertPoint(args[2 * i], args[2 * i + 1]) + args[2 * i] = pt.x; + args[2 * i + 1] = pt.y; + } + obj[prop](...args); + } + } else if (_tramat.indexOf(prop) >= 0) { + return function(...args) { + if (args.length >= 6) { + var pt = convertPoint(args[4], args[5]) + args[4] = pt.x; + args[5] = pt.y; + } + obj[prop](...args); + } + } else if (_txt.indexOf(prop) >= 0) { + return function(...args) { + if (args.length >= 3) { + var pt = convertPoint(args[1], args[2]) + args[1] = pt.x; + args[2] = pt.y; + } + if (args.length >= 4) { + args[3] = convertLen(args[3],0).x; + } + obj[prop](...args); + } + } else if (prop == "arc") { + return function(...args) { + //x, y, radius + if (args.length >= 2) { + var pt = convertPoint(args[0], args[1]) + args[0] = pt.x; + args[1] = pt.y; + } + if (args.length >= 3) { + args[2] = convertLen(args[2],0).x; + } + obj[prop](...args); + } + } else if (prop == "arcTo") { + return function(...args) { + //x1, y1, x2, y2, radius + if (args.length >= 2) { + var pt = convertPoint(args[0], args[1]) + args[0] = pt.x; + args[1] = pt.y; + } + if (args.length >= 4) { + var pt = convertPoint(args[2], args[3]) + args[2] = pt.x; + args[3] = pt.y; + } + if (args.length >= 5) { + args[4] = convertLen(args[4],0).x; + } + obj[prop](...args); + } + } else if (prop == "putImageData") { + //imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight + return function(...args) { + if (args.length >= 3) { + var pt = convertPoint(args[1], args[2]) + args[1] = pt.x; + args[2] = pt.y; + } + if (args.length >= 5) { + var pt = convertPoint(args[3], args[4]) + args[3] = pt.x; + args[4] = pt.y; + } + if (args.length >= 7) { + var pt = convertPoint(args[5], args[6]) + args[5] = pt.x; + args[6] = pt.y; + } + obj[prop](...args); + } + } else { + return function(...args) { + obj[prop](...args); + } + } + }, + set(obj, prop, val) { + var _lengthy = ["lineWidth"]; + if (_lengthy.indexOf(prop) >= 0) { + val = convertLen(val,0).x; + } + obj[prop] = val; + } + } + return new Proxy(base, handler); +} diff --git a/js/Helpers/SideSplit/coordinatedView.js b/js/Helpers/SideSplit/coordinatedView.js new file mode 100644 index 000000000..fceb352b9 --- /dev/null +++ b/js/Helpers/SideSplit/coordinatedView.js @@ -0,0 +1,31 @@ +function coordinatedView(viewer1, viewer2) { + /** Returns a callback which starts bidirectional view coordination + * run with window.setTimeout((this).initalize(viewer1, viewer2),500); + */ + + function initalize(){ + function transmit(from_viewer, to_viewer, reverse){ + return function(){ + var calib = document.getElementById('sbs_calibration').value.split(",").map((x)=>(parseFloat(x))) + var calib_point = new OpenSeadragon.Point(calib[0], calib[1]); + var active = document.getElementById('sbs_activation').value == "active" + if (active){ + var from_point = from_viewer.viewport.getCenter(); + var dest_point = new OpenSeadragon.Point(from_point.x, from_point.y).plus(calib_point); + if (reverse){ + var dest_point = new OpenSeadragon.Point(from_point.x, from_point.y).minus(calib_point); + } + to_viewer.viewport.zoomTo(from_viewer.viewport.getZoom(), dest_point, false); + to_viewer.viewport.panTo(dest_point, false); + } + } + } + var events=["click", "mouseover", "mousemove", "wheel", "keypress", "zoom", "pan"]; + events.forEach(function(ev){ + viewer1.container.addEventListener(ev ,transmit(viewer1,viewer2)); + viewer2.container.addEventListener(ev ,transmit(viewer2,viewer1, true)); + }) + + } + return initalize; +} diff --git a/js/Helpers/SideSplit/openseadragon-canvas-overlay.js b/js/Helpers/SideSplit/openseadragon-canvas-overlay.js new file mode 100644 index 000000000..fe7e0af1e --- /dev/null +++ b/js/Helpers/SideSplit/openseadragon-canvas-overlay.js @@ -0,0 +1,115 @@ +// OpenSeadragon canvas Overlay plugin 0.0.2 based on svg overlay plugin + +(function() { + + if (!window.OpenSeadragon) { + console.error('[openseadragon-canvas-overlay] requires OpenSeadragon'); + return; + } + + + // ---------- + OpenSeadragon.Viewer.prototype.canvasOverlay = function(options) { + + if (this._canvasOverlayInfo) { + return this._canvasOverlayInfo; + } + + this._canvasOverlayInfo = new Overlay(this,options); + return this._canvasOverlayInfo; + }; + + // ---------- + var Overlay = function(viewer,options) { + var self = this; + this._viewer = viewer; + + this._containerWidth = 0; + this._containerHeight = 0; + + this._canvasdiv = document.createElement( 'div'); + this._canvasdiv.style.position = 'absolute'; + this._canvasdiv.style.left = 0; + this._canvasdiv.style.top = 0; + this._canvasdiv.style.width = '100%'; + this._canvasdiv.style.height = '100%'; + this._viewer.canvas.appendChild(this._canvasdiv); + + this._canvas = document.createElement('canvas'); + this._canvasdiv.appendChild(this._canvas); + + this.onRedraw = options.onRedraw || function(){}; + this.clearBeforeRedraw = (typeof (options.clearBeforeRedraw) !== "undefined") ? + options.clearBeforeRedraw : true; + + + + this._viewer.addHandler('update-viewport', function() { + self.resize(); + self._updateCanvas(); + }); + + this._viewer.addHandler('open', function() { + self.resize(); + self._updateCanvas(); + }); + + + }; + + // ---------- + Overlay.prototype = { + // ---------- + canvas: function() { + return this._canvas; + }, + // ---------- + context2d: function() { + return this._canvas.getContext('2d'); + }, + // ---------- + clear: function() { + this._canvas.getContext('2d').clearRect(0, 0, this._containerWidth, this._containerHeight); + }, + // ---------- + resize: function() { + if (this._containerWidth !== this._viewer.container.clientWidth) { + this._containerWidth = this._viewer.container.clientWidth; + this._canvasdiv.setAttribute('width', this._containerWidth); + this._canvas.setAttribute('width', this._containerWidth); + } + + if (this._containerHeight !== this._viewer.container.clientHeight) { + this._containerHeight = this._viewer.container.clientHeight; + this._canvasdiv.setAttribute('height', this._containerHeight); + this._canvas.setAttribute('height', this._containerHeight); + } + this._viewportOrigin = new OpenSeadragon.Point(0, 0); + var boundsRect = this._viewer.viewport.getBounds(true); + this._viewportOrigin.x = boundsRect.x; + this._viewportOrigin.y = boundsRect.y * this.imgAspectRatio; + + this._viewportWidth = boundsRect.width; + this._viewportHeight = boundsRect.height * this.imgAspectRatio; + var image1 = this._viewer.world.getItemAt(0); + this.imgWidth = image1.source.dimensions.x; + this.imgHeight = image1.source.dimensions.y; + this.imgAspectRatio = this.imgWidth / this.imgHeight; + }, + _updateCanvas: function() { + var viewportZoom = this._viewer.viewport.getZoom(true); + var image1 = this._viewer.world.getItemAt(0); + var zoom = image1.viewportToImageZoom(viewportZoom); + + var x=((this._viewportOrigin.x/this.imgWidth-this._viewportOrigin.x )/this._viewportWidth)*this._containerWidth; + var y=((this._viewportOrigin.y/this.imgHeight-this._viewportOrigin.y )/this._viewportHeight)*this._containerHeight; + + if (this.clearBeforeRedraw) this.clear(); + this._canvas.getContext('2d').translate(x,y); + this._canvas.getContext('2d').scale(zoom,zoom); + this.onRedraw(); + this._canvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0); + } + }; + +})(); diff --git a/js/Helpers/SideSplit/run_sidesplit.js b/js/Helpers/SideSplit/run_sidesplit.js new file mode 100644 index 000000000..2ff8eec4d --- /dev/null +++ b/js/Helpers/SideSplit/run_sidesplit.js @@ -0,0 +1,111 @@ +var annots; + +var _sbs_source = _viewer_source; +var _sbs_id = tissueId; + +// call this function before minidraw to open a different image +function change_image(id, url){ + _sbs_source = url; + _sbs_id = id; +} + +// create a div for the algorithm selector +var algsel = document.createElement("div"); +algsel.style.zIndex = "99"; +algsel.style.padding = "10px;" +algsel.style.position = "absolute"; +algsel.style.height = "auto"; +algsel.style.maxHeight = "80%"; +algsel.style.overflow = "auto"; +algsel.style.width = "30%"; +algsel.style.top = "10%"; +algsel.style.left = "60%"; +algsel.style.display = "none"; +algsel.style.borderRadius= "5px"; +algsel.style.background= "#1764d8"; +algsel.style.color = "white"; + + +algsel.id = "algsel_sbs"; +document.body.appendChild(algsel); + +var firstInit = true; + +function show_minidraw(){ + if (firstInit){ + firstInit = false; + // calibrate our canvas + var c1 = delayer({}); + var c1_c = ViewportCalibratedCanvas(c1, rhs_viewer); + var rhs_imagingHelper = new OpenSeadragonImaging.ImagingHelper({ + viewer: rhs_viewer + }); + // handle algorithm selection + annots = new annotations(_sbs_id, rhs_viewer, c1_c, rhs_imagingHelper, {}); + + // get new data each pass + rhs_viewer.addHandler("zoom", function(){ + annots.draw(); + }) + + rhs_viewer.addHandler("pan", function(){ + annots.draw(); + }); + + // redraw all active annotations each redraw + // clearing and re-fetching is inefficient, c1 can be used as a cache + var overlay = rhs_viewer.canvasOverlay({ + clearBeforeRedraw:true, + onRedraw:function() { + var lw = 50 / (viewer.viewport.getZoom(true)); + overlay.context2d().lineWidth = lw + c1.__apply_all(overlay.context2d()); + } + }); + } + // reset each time + annots.selection = []; + // algorithm selector + annots.store.getAlgList(function(data){ + let algsel = document.getElementById("algsel_sbs"); + algsel.innerHTML = ""; + algsel.style.display = "inline-block"; + let title = document.createElement("div"); + title.innerHTML = "Select algorithms:
" + algsel.appendChild(title); + data.forEach(function(x){ + let select_item = document.createElement("div"); + select_item.innerHTML = x.title; + select_item.onclick = function(y){ + y = y.target; + y.style.display="none"; + annots.select(y.innerHTML); + // force a redraw + annots.forceDraw(); + }.bind(this); + // TODO add a little color indicator + algsel.appendChild(select_item); + }); + let done = document.createElement("div"); + done.innerHTML = "DONE" + done.onclick = function(){ + document.getElementById("algsel_sbs").style.display="none"; + } + algsel.appendChild(done); + }); +} + + + +// functions to change + +document.addEventListener("sidesplit", function(e){ + if (document.getElementById("right_sidebyside").style.display == "block"){ + hide_sbs(); + } else { + // need viewers to be up to draw + show_sbs(); + show_minidraw(); + rhs_viewer.open(_sbs_source); + } +}); diff --git a/js/Helpers/Spyglass.js b/js/Helpers/Spyglass.js new file mode 100644 index 000000000..7f5f95e94 --- /dev/null +++ b/js/Helpers/Spyglass.js @@ -0,0 +1,28 @@ +/** **/ +function Spyglass(viewer, modal_viewer) { + /** + * Creates a callback which starts single window magnifitation code + * Include this file and start with something like: + * window.setTimeout(Spyglass(viewer, modal_viewer),500); + */ + // return a callback + return function() { + // set default to max zoom + document.getElementById(modal_viewer.id)['zoomlevel'] = document.getElementById(modal_viewer.id)['zoomlevel'] || modal_viewer.viewport.getMaxZoom(); + document.getElementById(modal_viewer.id).style.position = "absolute"; + var tracker = new OpenSeadragon.MouseTracker({ + element: viewer.container, + moveHandler: function(e) { + var pt = viewer.viewport.pointFromPixel(e.position); + modal_viewer.viewport.zoomTo(document.getElementById(modal_viewer.id)['zoomlevel']); + modal_viewer.viewport.panTo(pt); + } + }); + tracker.setTracking(true); + document.onmousemove = function(e) { + document.getElementById(modal_viewer.id).style.left = -document.getElementById(modal_viewer.id).clientWidth + e.clientX - 20 + "px"; + document.getElementById(modal_viewer.id).style.top = -document.getElementById(modal_viewer.id).clientHeight + e.clientY - 20 + "px"; + } + } + +} diff --git a/js/Helpers/StateManager.js b/js/Helpers/StateManager.js new file mode 100644 index 000000000..507c5b467 --- /dev/null +++ b/js/Helpers/StateManager.js @@ -0,0 +1,117 @@ +/* StateManager + * @constructor + * @param prefix - the prefix for the state url component (i.e. ?{prefix}=abc) + */ +class StateManager { + + // TODO more sensible method names + constructor(prefix) { + this.prefix = prefix; + this.vals = {}; + this.setters = {}; + } + + /* Add a key to the state variable */ + add_key(name, callback) { + /* Register a new key + * @param name - the unique name of the key + * @param callback - what to do with the value if present on load + * then use (this).vals['key'] to set key values + * run (this).set_url(); to update the url with all set key values + */ + this.setters[name] = callback; + } + + encode(state_object) { + /* encoding for state into url + * @param state_object - the object to encode + * uses base64 encoding + * "exotic" objects likely won't work correctly without a way to convert to and from string + */ + return encodeURIComponent(btoa(JSON.stringify(state_object))); + } + + decode(encoded_string) { + /* decoding for state from url + * @param encoded_string - the encoded string + * uses base64 decoding + * "exotic" objects likely won't work correctly without a way to convert to and from string + */ + return JSON.parse(atob(decodeURIComponent(encoded_string))); + } + + set_url() { + /* Sets the current state into the url + * This updates the string to reflect all set (this).vals for all keys + */ + var state_string = this.encode(this.vals); + // get all url components + var previous = location.search.substring(1); + var p_var = previous ? JSON.parse('{"' + previous.replace(/&/g, '","').replace(/=/g, '":"') + '"}', + function(key, value) { + return key === "" ? value : decodeURIComponent(value) + }) : {} + // switch out our state value + p_var[this.prefix] = state_string; + // put paramater string back together, as modified + var params = Object.keys(p_var).map((i) => i + '=' + p_var[i]).join('&'); + window.history.replaceState({}, document.title,location.pathname + "?" + params); + } + + get_url_state() { + /* fetches all state information from the current url + */ + // get all url components + var previous = location.search.substring(1); + var p_var = previous ? JSON.parse('{"' + previous.replace(/&/g, '","').replace(/=/g, '":"') + '"}', + function(key, value) { + return key === "" ? value : decodeURIComponent(value) + }) : {} + // return ours + return p_var[this.prefix]; + } + + clear_url() { + /* remove this param from the url + */ + var previous = location.search.substring(1); + var p_var = previous ? JSON.parse('{"' + previous.replace(/&/g, '","').replace(/=/g, '":"') + '"}', + function(key, value) { + return key === "" ? value : decodeURIComponent(value) + }) : {} + // pull out our state value + delete p_var[this.prefix]; + var params = Object.keys(p_var).map((i) => i + '=' + p_var[i]).join('&'); + window.history.replaceState({}, document.title,location.pathname + "?" + params); + } + + initialize(state) { + /* run all set functions based on the url and registry */ + for (var i in state) { + if (i in this.setters) { + this.setters[i](state[i]); + } + } + } + + to_storage(key) { + /* copy state from url component to local storage + * @param key - the key to store under localstorage + */ + localStorage.setItem(key, this.get_url_state()); + } + + from_storage(key) { + /* copy state from local storage to url component + * @param key - the key to retrieve under localstorage + */ + return localStorage.getItem(key); + } + + + +} + +if (typeof module !== 'undefined' && module.exports != null) { + exports.StateManager = StateManager; +} diff --git a/js/Helpers/StateSchema.js b/js/Helpers/StateSchema.js new file mode 100644 index 000000000..17622d535 --- /dev/null +++ b/js/Helpers/StateSchema.js @@ -0,0 +1,55 @@ +// this code helps us define our schema for state mangment +// schema : {position:{x:x,y:y,z:z}, algs:[algname1,algname2]} +var camic_state = new StateManager('state'); + +function setPosition(position){ + var pt = new OpenSeadragon.Point(position.x, position.y); + viewer.viewport.zoomTo(position.z, pt); + viewer.viewport.panTo(pt, true); +} + +// TODO test if this method always works +function setAlgs(algList){ + // requires annotool to contain SELECTED_ALGORITHM_LIST + SELECTED_ALGORITHM_LIST = algList; +} + +// initalize after 500 mseconds +viewer.addHandler('open',function(){ + camic_state.add_key('position', setPosition); + camic_state.add_key('alg', setAlgs); + // before touching the url, get what we already have + try{ + var x = camic_state.get_url_state(); + console.log("camic_state.get_url_state()", x); + if (x) + { + camic_state.initialize(camic_state.decode(x)); + } + //camic_state.initialize(camic_state.decode(camic_state.get_url_state())); + } + catch(e){ + console.log(e); + } +}); + + +algHandler = function() { + camic_state.vals['alg'] = SELECTED_ALGORITHM_LIST; + //camic_state.set_url(); +}; + +moveHandler = function() { + var pos = viewer.viewport.getCenter(true); + var zoom = viewer.viewport.getZoom(true); + camic_state.vals['position']={'x':pos.x, 'y':pos.y, 'z':zoom}; + //camic_state.set_url(); +}; + +// TODO make this actually trigger usefully +// update url when requested only (this should be share) +function LinkRequest(){ + moveHandler(); + algHandler(); + console.log("{state : " + camic_state.encode(camic_state.vals)+ "}"); +} diff --git a/js/Helpers/session_notify.js b/js/Helpers/session_notify.js new file mode 100644 index 000000000..e630b4e64 --- /dev/null +++ b/js/Helpers/session_notify.js @@ -0,0 +1,12 @@ +window.setInterval(function(){ + fetch("../security/checkStatus.php", {method: 'post'}) + .then(function(x){ + return x.json() + }) + .then(function(rsp){ + if (rsp.issued && (rsp.now - rsp.issued > 60*50)){ + window.alert("Your session has expired.") + } + }) + .catch((x)=>console.warn(x)); +}, (1000*60*5)); diff --git a/js/Helpers/spyglass_init_camic.js b/js/Helpers/spyglass_init_camic.js new file mode 100644 index 000000000..a99699473 --- /dev/null +++ b/js/Helpers/spyglass_init_camic.js @@ -0,0 +1,46 @@ + +// this initalizes spyglass for caMicroscope +// OSD and Spyglass.js need to be included before this. + +function toggle_spyglass_visible(){ + is_invisible = document.getElementById('spyglass').offsetParent === null + is_invisible ? document.getElementById('spyglass').style.display = "" : document.getElementById('spyglass').style.display = "none"; +} + +function spyglass_init(imgsrc){ + // create the div + + var spyglass_div = document.createElement("div"); + spyglass_div.id = "spyglass" + // style it + spyglass_div.style['z-index'] = "1"; + spyglass_div.style['width'] = "20%"; + spyglass_div.style['height'] = "20%"; + spyglass_div.style['border'] = "5px solid black"; + spyglass_div.style['border-radius'] = "5px"; + spyglass_div.style['z-index'] = "1"; + spyglass_div.style['display'] = "none"; + document.body.appendChild(spyglass_div); + // init OSD + var spyglass_viewer = new OpenSeadragon.Viewer({ + id: "spyglass", + prefixUrl: "images/", + showNavigationControl : false + }); + // open image + spyglass_viewer.open(imgsrc); + //add to toolbar + + // call the spyglass +Spyglass(viewer, spyglass_viewer)(); + + // make the button not hidden + + // things we need to wait on to resolve +document.addEventListener("magnifier-button-loaded",function(){ + document.getElementById('spyglass_toolbar_button').style = ""; + document.getElementById('spyglass_toolbar_button').onclick = toggle_spyglass_visible; + // TODO remove this and handle custom zoom + document.getElementById('spyglass')['zoomlevel'] = viewer.viewport.getMaxZoom(); + }); +} diff --git a/js/Helpers/test/HelperUnitTests.js b/js/Helpers/test/HelperUnitTests.js new file mode 100644 index 000000000..ea164603c --- /dev/null +++ b/js/Helpers/test/HelperUnitTests.js @@ -0,0 +1,23 @@ +const { expect } = require('chai'); +global.atob = require('atob'); +global.btoa = require('btoa'); + +StateManager = require("../StateManager.js").StateManager; + +describe('State Manager', function () { + var camic_state; + var state_test_obj = {"a": 1, "b":[1,2], "c": {"valid": true}} + var state_str; + it('should construct', async function () { + camic_state = new StateManager('state'); + expect(camic_state).to.exist; + }); + it('should encode', async function () { + state_str = camic_state.encode(state_test_obj) + expect(state_str).to.exist; + }); + it('should decode to the same as the input', async function () { + var res_str = camic_state.decode(state_str) + expect(res_str).to.deep.include(state_test_obj); + }); +}); diff --git a/js/annotationtools/AnnotationStore.js b/js/annotationtools/AnnotationStore.js index 91aee6961..2e52eaeb6 100644 --- a/js/annotationtools/AnnotationStore.js +++ b/js/annotationtools/AnnotationStore.js @@ -1,161 +1,163 @@ var AnnotationStore = function (iid) { - this.annotations = [] - this.iid = iid - this.cacheBounds = { - x1: 100, - y1: -1, - x2: 1, - y2: 2 - } -} + this.annotations = []; + this.iid = iid; + this.cacheBounds = { + x1: 100, + y1: -1, + x2: 1, + y2: 2 + } +}; AnnotationStore.prototype.getAnnotations = function (x1, y1, x2, y2, footprint, algorithms, boundX1, boundY1, boundX2, boundY2, callback) { - var self = this + var self = this; - if (Math.round(footprint) != 16) { - self.setCacheBounds(100, -1, 1, 2) + if (Math.round(footprint) != 16) { + self.setCacheBounds(100, -1, 1, 2); - var annotations = this.fetchAnnotations(x1, y1, x2, y2, footprint, algorithms, callback) - } else { - if (this.cacheBounds.x1 > x1 || this.cacheBounds.y1 > y1 || this.cacheBounds.x2 < x2 || this.cacheBounds.y2 < y2) { - if (this.cacheBounds.x1 > x1) { - console.log('x lower bound') - } - if (this.cacheBounds.y1 > y1) { - console.log('y lower bound') - } - if (this.cacheBounds.x2 < x2) { - console.log('x upper bound') - } - if (this.cacheBounds.y2 < y2) { - console.log('y upper bound') - } - - var x_1 = x1 - boundX1 - var y_1 = y1 - boundY1 - var x_2 = x2 + boundX2 - var y_2 = y2 + boundY2 - if (x_1 < 0) - x_1 = 0 - if (y_1 < 0) - y_1 = 0 - - self.setCacheBounds(x_1, y_1, x_2, y_2) - // console.log("fetching.........") - console.log('Clearing and fetching cache') - var annotations = this.fetchAnnotations(x_1, y_1, x_2, y_2, footprint, algorithms, callback) + var annotations = this.fetchAnnotations(x1, y1, x2, y2, footprint, algorithms, callback) } else { - console.log('from cache') - callback(self.annotations) + if (this.cacheBounds.x1 > x1 || this.cacheBounds.y1 > y1 || this.cacheBounds.x2 < x2 || this.cacheBounds.y2 < y2) { + if (this.cacheBounds.x1 > x1) { + console.log('x lower bound') + } + if (this.cacheBounds.y1 > y1) { + console.log('y lower bound') + } + if (this.cacheBounds.x2 < x2) { + console.log('x upper bound') + } + if (this.cacheBounds.y2 < y2) { + console.log('y upper bound') + } + + var x_1 = x1 - boundX1; + var y_1 = y1 - boundY1; + var x_2 = x2 + boundX2; + var y_2 = y2 + boundY2; + if (x_1 < 0) + x_1 = 0; + if (y_1 < 0) + y_1 = 0; + + self.setCacheBounds(x_1, y_1, x_2, y_2); + // console.log("fetching.........") + console.log('Clearing and fetching cache'); + var annotations = this.fetchAnnotations(x_1, y_1, x_2, y_2, footprint, algorithms, callback) + } else { + console.log('from cache'); + callback(self.annotations) + } } - } -} +}; AnnotationStore.prototype.setCacheBounds = function (x1, y1, x2, y2) { - this.cacheBounds.x1 = x1 - this.cacheBounds.x2 = x2 - this.cacheBounds.y1 = y1 - this.cacheBounds.y2 = y2 -} + this.cacheBounds.x1 = x1; + this.cacheBounds.x2 = x2; + this.cacheBounds.y1 = y1; + this.cacheBounds.y2 = y2 +}; AnnotationStore.prototype.getCacheBounds = function () { - return this.cacheBounds -} + return this.cacheBounds +}; AnnotationStore.prototype.fetchAnnotations = function (x1, y1, x2, y2, footprint, algorithms, callback) { - var self = this - if (footprint == 16) - console.log(footprint) - var midX = x2 - var midY = y2 - /* - var algorithms_urlparam = JSON.stringify(algorithms) - algorithms_urlparam = algorithms_urlparam.replace('[', '%5B') - algorithms_urlparam = algorithms_urlparam.replace(']', '%5D') - algorithms_urlparam = algorithms_urlparam.replace(/"/g, '%22') - - //dispaly composite_input annotation while in low scale viewport - var isCompositeAnnotationOnly= true; - var algorithm_number = algorithms.length; - if (algorithm_number >0) { - for (i=0; i< algorithm_number; i++){ - var index=algorithms[i].indexOf("composite_input"); - //not find composite annotation - if(index == -1){ - isCompositeAnnotationOnly= false;} - } - } - if(algorithm_number >0 && isCompositeAnnotationOnly) - footprint = 1 ; //find composite_input annotation only - - var url1 = 'api/Data/getMultipleAnnots.php?iid=' + self.iid + '&x=' + x1 + '&y=' + y1 + '&x1=' + midX + '&y1=' + midY + '&footprint=' + footprint + '&algorithms=' + algorithms_urlparam - console.log(url1) - */ - - //dispaly composite_input annotation while in low scale viewport - var isCompositeAnnotationOnly= true; - var isNonCompositeAnnotationOnly=true; - var algorithms_computer= []; - var algorithms_human = []; - - var algorithm_number = algorithms.length; - - if (algorithm_number >0) { - for (i=0; i< algorithm_number; i++){ - var index=algorithms[i].indexOf("composite_input"); - //not find composite annotation - if(index == -1){ - isCompositeAnnotationOnly= false; - algorithms_computer.push(algorithms[i]); - } - - if(index != -1){ - isNonCompositeAnnotationOnly= false; - algorithms_human.push(algorithms[i]); - } - } - } - - if(algorithm_number >0 && isCompositeAnnotationOnly) - footprint = 1 ; //find composite_input annotation only - - var algorithms_urlparam = JSON.stringify(algorithms); + var self = this; + if (footprint == 16) + console.log(footprint); + var midX = x2; + var midY = y2; + + /* + var algorithms_urlparam = JSON.stringify(algorithms) + algorithms_urlparam = algorithms_urlparam.replace('[', '%5B') + algorithms_urlparam = algorithms_urlparam.replace(']', '%5D') + algorithms_urlparam = algorithms_urlparam.replace(/"/g, '%22') + + //display composite_input annotation while in low scale viewport + var isCompositeAnnotationOnly= true; + var algorithm_number = algorithms.length; + if (algorithm_number >0) { + for (i=0; i< algorithm_number; i++){ + var index=algorithms[i].indexOf("composite_input"); + //not find composite annotation + if(index == -1){ + isCompositeAnnotationOnly= false;} + } + } + if(algorithm_number >0 && isCompositeAnnotationOnly) + footprint = 1 ; //find composite_input annotation only + + var url1 = 'api/Data/getMultipleAnnots.php?iid=' + self.iid + '&x=' + x1 + '&y=' + y1 + '&x1=' + midX + '&y1=' + midY + '&footprint=' + footprint + '&algorithms=' + algorithms_urlparam + console.log(url1) + */ + + //display composite_input annotation while in low scale viewport + var isCompositeAnnotationOnly = true; + var isNonCompositeAnnotationOnly = true; + var algorithms_computer = []; + var algorithms_human = []; + + var algorithm_number = algorithms.length; + + if (algorithm_number > 0) { + for (i = 0; i < algorithm_number; i++) { + var index = algorithms[i].indexOf("composite_input"); + //not find composite annotation + if (index == -1) { + isCompositeAnnotationOnly = false; + algorithms_computer.push(algorithms[i]); + } + + if (index != -1) { + isNonCompositeAnnotationOnly = false; + algorithms_human.push(algorithms[i]); + } + } + } + + if (algorithm_number > 0 && isCompositeAnnotationOnly) + footprint = 1; //find composite_input annotation only + + var algorithms_urlparam = JSON.stringify(algorithms); algorithms_urlparam = algorithms_urlparam.replace("[", "%5B"); algorithms_urlparam = algorithms_urlparam.replace("]", "%5D"); algorithms_urlparam = algorithms_urlparam.replace(/"/g, "%22"); - - var algorithms_urlparam_computer = JSON.stringify(algorithms_computer); + + var algorithms_urlparam_computer = JSON.stringify(algorithms_computer); algorithms_urlparam_computer = algorithms_urlparam_computer.replace("[", "%5B"); algorithms_urlparam_computer = algorithms_urlparam_computer.replace("]", "%5D"); algorithms_urlparam_computer = algorithms_urlparam_computer.replace(/"/g, "%22"); - - var algorithms_urlparam_human = JSON.stringify(algorithms_human); + + var algorithms_urlparam_human = JSON.stringify(algorithms_human); algorithms_urlparam_human = algorithms_urlparam_human.replace("[", "%5B"); algorithms_urlparam_human = algorithms_urlparam_human.replace("]", "%5D"); algorithms_urlparam_human = algorithms_urlparam_human.replace(/"/g, "%22"); - + //console.log(algorithms_urlparam); var url1; - + //if(isCompositeAnnotationOnly || isNonCompositeAnnotationOnly) { - //url1 = "api/Data/getMultipleAnnotsClone.php?iid="+ self.iid +"&x=" + x1+ "&y=" + y1 + "&x1=" + midX + "&y1=" + midY + "&footprint="+ footprint + "&algorithms=" + algorithms_urlparam; - //}else { - url1 = "api/Data/getMultipleAnnotationsNew.php?iid="+ self.iid +"&x=" + x1+ "&y=" + y1 + "&x1=" + midX + "&y1=" + midY + "&footprint="+ footprint + "&algorithms_computer=" + algorithms_urlparam_computer+ "&algorithms_human=" + algorithms_urlparam_human; - //} - - //console.log(url1); - - jQuery.get(url1, function (data) { - //console.log(data); - var d = {}; - try{ - - d = JSON.parse(data); - } catch(e){ - d = []; - } - self.annotations = d - if (callback) - callback(d) - }) -} + //url1 = "api/Data/getMultipleAnnotsClone.php?iid="+ self.iid +"&x=" + x1+ "&y=" + y1 + "&x1=" + midX + "&y1=" + midY + "&footprint="+ footprint + "&algorithms=" + algorithms_urlparam; + //}else { + url1 = "api/Data/getMultipleAnnotationsNew.php?iid=" + self.iid + "&x=" + x1 + "&y=" + y1 + "&x1=" + midX + "&y1=" + midY + "&footprint=" + footprint + "&algorithms_computer=" + algorithms_urlparam_computer + "&algorithms_human=" + algorithms_urlparam_human; + //} + //console.log(url1); + //url1 = "api/Data/getMultipleAnnots.php?iid=" + self.iid + "&x=" + x1 + "&y=" + y1 + "&x1=" + midX + "&y1=" + midY + "&footprint=" + footprint + "&algorithms=" + algorithms_urlparam; + + + jQuery.get(url1, function (data) { + //console.log(data); + var d = {}; + try { + + d = JSON.parse(data); + } catch (e) { + d = []; + } + self.annotations = d; + if (callback) + callback(d) + }) +}; diff --git a/js/annotationtools/SegQualHeatmap.svg b/js/annotationtools/SegQualHeatmap.svg new file mode 100644 index 000000000..183a1a3f5 --- /dev/null +++ b/js/annotationtools/SegQualHeatmap.svg @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/js/annotationtools/ToolBar.js b/js/annotationtools/ToolBar.js index 3c6871acf..330e81e13 100644 --- a/js/annotationtools/ToolBar.js +++ b/js/annotationtools/ToolBar.js @@ -1,707 +1,359 @@ /** - * Get option values for "tool" element, else set default values. - * - * @param element - * @param options - * @constructor + * TOOLBAR + * CAMICROSCOPE */ -var ToolBar = function (element, options) { - // console.log(options) - this.annotools = options.annotool - // console.log(this.annotools) - this.FilterTools = options.FilterTools - this.source = element // The Tool Source Element - this.top = options.top || '0px' - this.left = options.left || '150px' // The Tool Location - this.height = options.height || '30px' - this.width = options.width || '270px' - this.zindex = options.zindex || '100' // To Make Sure The Tool Appears in the Front - - this.iid = options.iid || null - this.annotationActive = isAnnotationActive() -} +$.getScript('shared/ToolBar.js', function () { -/** - * Print message to console. - * @param msg - */ -ToolBar.prototype.showMessage = function (msg) { - console.log(msg) -} - -ToolBar.prototype.algorithmSelector = function () { - var self = this - var ftree - xxx = [] -} - - -//var available_colors = ['lime', 'red', 'blue', 'orange','lime', 'red', 'blue', 'orange','lime', 'red', 'blue', 'orange'] -var available_colors = ['#a6cee3', '#1f78b4', '#b2df8a', '#33a02c', '#fb9a99', '#e31a1c', '#fdbf6f', '#ff7f00', '#cab2d6', '#6a3d9a', '#ffff99', '#b15928']; - -var algorithm_color = {} - -function goodalgo(data, status) { - // console.log(data) - - var blob = [] - for (i = 0; i < data.length; i++) { - var n = {} - - data[i].title = data[i].provenance.analysis_execution_id; - - n.title = "
" + data[i].title; - n.key = i.toString() - n.refKey = data[i].provenance.analysis_execution_id - n.color = available_colors[i % 7]; - //algorithm_color[data[i].provenance.analysis_execution_id] = available_colors[i%7] - algorithm_color[data[i].provenance.analysis_execution_id] = available_colors[i % available_colors.length]; - blob.push(n) - } - ftree = jQuery('#tree').fancytree({ - source: [{ - title: 'Algorithms', key: '1', folder: true, - children: blob, - expanded: true - }], - minExpandLevel: 1, // 1: root node is not collapsible - activeVisible: true, // Make sure, active nodes are visible (expanded). - aria: false, // Enable WAI-ARIA support. - autoActivate: true, // Automatically activate a node when it is focused (using keys). - autoCollapse: false, // Automatically collapse all siblings, when a node is expanded. - autoScroll: false, // Automatically scroll nodes into visible area. - clickFolderMode: 4, // 1:activate, 2:expand, 3:activate and expand, 4:activate (dblclick expands) - checkbox: true, // Show checkboxes. - debugLevel: 2, // 0:quiet, 1:normal, 2:debug - disabled: false, // Disable control - focusOnSelect: false, // Set focus when node is checked by a mouse click - generateIds: false, // Generate id attributes like - idPrefix: 'ft_', // Used to generate node id´s like . - icons: true, // Display node icons. - keyboard: true, // Support keyboard navigation. - keyPathSeparator: '/', // Used by node.getKeyPath() and tree.loadKeyPath(). - quicksearch: false, // Navigate to next node by typing the first letters. - selectMode: 2, // 1:single, 2:multi, 3:multi-hier - tabbable: true, // Whole tree behaves as one single control - titlesTabbable: false, // Node titles can receive keyboard focus - beforeSelect: function (event, data) { - // A node is about to be selected: prevent this for folders: - if (data.node.isFolder()) { - return false - } - }, - select: function (event, data) { - jQuery('#tree').attr('algotree', true) - var node = data.node - - console.log('!SELECTED NODE : ' + node.title) - targetType = data.targetType - annotool.getMultiAnnot() - } - }) -} -var ALGORITHM_LIST = {}; -var SELECTED_ALGORITHM_LIST = []; -var SELECTED_ALGORITHM_KEYS = []; -var SELECTED_ALGORITHM_COLOR = {}; -var AlgorithmSelectorHidden = true; - -/** - * Show/Hide "Select Algorithm" menu - */ -ToolBar.prototype.toggleAlgorithmSelector = function () { - var self = this; - console.log("toggleAlgorithmSelector"); - //jQuery("#panel").show("slide"); - var url = 'api/Data/getAlgorithmsForImage.php?iid=' + self.iid; - - var htmlStr = "

Select Algorithm

    "; - jQuery.get(url, function (data) { - - d = JSON.parse(data) - -// sorting the algorithms - var tmp_algorithm_list = []; - for (var i = 0; i < d.length; i++) { - tmp_algorithm_list[i] = d[i].provenance.analysis_execution_id; - } - //tmp_algorithm_list = tmp_algorithm_list.sort(); - var algorithms_computer = []; - var algorithms_composite_input = []; - var algorithms_composite_dataset = []; - var algorithms_under = []; - var algorithms_over = []; - - var algorithm_number = tmp_algorithm_list.length; - if (algorithm_number > 0) { - - for (i = 0; i < algorithm_number; i++) { - var index_composite_input = tmp_algorithm_list[i].indexOf("composite_input"); - var index_composite_dataset = tmp_algorithm_list[i].indexOf("composite_dataset"); - var index_under = tmp_algorithm_list[i].indexOf("under_"); - var index_over = tmp_algorithm_list[i].indexOf("over_"); - - if (index_composite_input != -1) { - algorithms_composite_input.push(tmp_algorithm_list[i]); - } else if (index_composite_dataset != -1) { - algorithms_composite_dataset.push(tmp_algorithm_list[i]); - } else if (index_under != -1) { - algorithms_under.push(tmp_algorithm_list[i]); - } else if (index_over != -1) { - algorithms_over.push(tmp_algorithm_list[i]); - } else { - algorithms_computer.push(tmp_algorithm_list[i]); - } - } - algorithms_computer = algorithms_computer.sort(); - algorithms_under = algorithms_under.sort(); - algorithms_over =algorithms_over.sort(); - algorithms_composite_input=algorithms_composite_input.sort(); - algorithms_composite_dataset = algorithms_composite_dataset.sort(); - tmp_algorithm_list = algorithms_computer.concat(algorithms_under, algorithms_over, algorithms_composite_input, algorithms_composite_dataset); - } + /** + * Create Buttons + */ + ToolBar.prototype.createButtons = function () { - ALGORITHM_LIST = d; - for (var i = 0; i < tmp_algorithm_list.length; i++) { - algorithm_color[tmp_algorithm_list[i]] = available_colors[i % available_colors.length]; - SELECTED_ALGORITHM_COLOR[tmp_algorithm_list[i]] = available_colors[i % available_colors.length]; - htmlStr += "
  • " + tmp_algorithm_list[i] - + "
  • "; - } + // this.tool = jQ(this.source) + var tool = jQuery('#' + 'tool'); // Temporary dom element while we clean up mootools + var self = this; - htmlStr += "

"; + // Fetch algorithms for Image + jQuery(document).ready(function () { + // var self= this - jQuery("#panel").html(htmlStr); + jQuery.get('api/Data/getAlgorithmsForImage.php?iid=' + self.iid, function (data) { + d = JSON.parse(data); - /** - * Open Select Algorithm menu. - */ - jQuery("#algorithmList input[type=checkbox]").each(function () { - - var elem = jQuery(this) - var id = (this).value * 1; - for (var i = 0; i < SELECTED_ALGORITHM_KEYS.length; i++) { - if (SELECTED_ALGORITHM_KEYS[i] == (id)) { + goodalgo(d, null); + }); - elem.prop('checked', true); + jQuery('#submitbtn').click(function () { + var selKeys = jQuery('#tree').fancytree('getTree').getSelectedNodes(); + var param = ''; + for (i = 0; i < selKeys.length; i++) { + param = param + '&Val' + (i + 1).toString() + '=' + selKeys[i].title; } - } - + }); + }); + tool.css({ + 'position': 'absolute', + 'left': this.left, + 'top': this.top, + 'width': this.width, + 'height': this.height, + 'z-index': this.zindex }); - self.annotools.getMultiAnnot(); + tool.addClass('annotools'); // Update Styles + // this.tool.makeDraggable(); //Make it Draggable. /** - * Select algorithm from menu. + * Set up Toolbar buttons */ - jQuery('#algorithmList input[type=checkbox]').change(function () { - console.log("change"); - SELECTED_ALGORITHM_LIST = []; - SELECTED_ALGORITHM_KEYS = []; - jQuery("#algorithmList input:checked").each(function () { - console.log("algorithm list:", ALGORITHM_LIST); - SELECTED_ALGORITHM_LIST.push(tmp_algorithm_list[(this).value * 1]); - SELECTED_ALGORITHM_KEYS.push((this).value * 1); - }); - - self.annotools.getMultiAnnot(); - + if (this.annotationActive) { - }) - - /* - jQuery("#submitAlgorithms").click(function(){ - var selected= []; - SELECTED_ALGORITHM_LIST = []; - jQuery("#algorithmList input:checked").each(function() { - SELECTED_ALGORITHM_LIST.push(ALGORITHM_LIST[(this).value * 1].analysis.execution_id); - SELECTED_ALGORITHM_KEYS.push((this).value*1); - }); - - self.annotools.getMultiAnnot(); - jQuery("#panel").html(""); - jQuery("#panel").hide("slide"); - }); - */ - - jQuery("#cancelAlgorithms").click(function () { - jQuery("#panel").html(""); - jQuery("#panel").hide("slide"); - AlgorithmSelectorHidden = true; - }); - }); - - if (AlgorithmSelectorHidden == true) { - jQuery("#panel").show("slide"); - AlgorithmSelectorHidden = false; - } else { - jQuery("#panel").html(""); - jQuery("#panel").hide("slide"); - - AlgorithmSelectorHidden = true; - } - -} - -ToolBar.prototype.createButtons = function () { - console.log("createButtons"); - - // this.tool = jQ(this.source) - var tool = jQuery('#' + 'tool') // Temporary dom element while we clean up mootools - var self = this - - // Fetch algorithms for Image - jQuery(document).ready(function () { - // var self= this - var url = 'api/Data/getAlgorithmsForImage.php?iid=' + self.iid; - console.log("data url:", url); - jQuery.get(url, function (data) { - //console.log(data); - d = JSON.parse(data); - - goodalgo(d, null); - }); - - jQuery('#submitbtn').click(function () { - var selKeys = jQuery('#tree').fancytree('getTree').getSelectedNodes(); - var param = ''; - for (i = 0; i < selKeys.length; i++) { - param = param + '&Val' + (i + 1).toString() + '=' + selKeys[i].title; - } - }); - }); + /* Go home, go camicro */ + this.homebutton = jQuery('', { + title: 'QuIP Home', + class: 'toolButton firstToolButtonSpace inactive', + src: 'images/ic_home_white_24px.svg' + }); + tool.append(this.homebutton); - tool.css({ - 'position': 'absolute', - 'left': this.left, - 'top': this.top, - 'width': this.width, - 'height': this.height, - 'z-index': this.zindex - }) + /* space */ + this.spacer1 = jQuery('', { + 'class': 'spacerButton inactive', + 'src': 'images/spacer_empty.svg' + }); + tool.append(this.spacer1); - tool.addClass('annotools') // Update Styles - // this.tool.makeDraggable(); //Make it Draggable. + /* Go lymphocytes, go segment curation */ + this.lymphbutton = jQuery('', { + 'title': 'Lymphocyte & Plasma Cell Annotation App', + 'class': 'toolButton inactive', + 'src': 'images/Heatmap.svg' + }); + tool.append(this.lymphbutton); // Lymphocyte Button +/* + this.qualitybutton = jQuery('', { + 'data-toggle': 'tooltip', + 'data-placement': 'bottom', + 'title': 'Segmentation Quality Heatmaps', + 'class': 'toolButton', + 'src': 'images/cellseg.svg' + }); - /** - * Set up Toolbar buttons - */ - if (this.annotationActive) { + tool.append(this.qualitybutton); // Lymphocyte Button +*/ + this.spacer1 = jQuery('', { + 'class': 'spacerButton', + 'src': 'images/spacer.svg' + }); + tool.append(this.spacer1); + + /*a link to segment curation application with this composite button */ + this.compositebutton = jQuery('', { + 'data-toggle': 'tooltip', + 'data-placement': 'bottom', + title: 'Segment Curation App', + class: 'toolButton', + src: 'images/composite.png', + id: 'gotocompositebutton' + }); + tool.append(this.compositebutton); + + /* space */ + tool.append(jQuery('', { + 'class': 'spacerButton inactive', + 'src': 'images/spacer_empty.svg' + })); + + /* App tools */ + this.filterbutton = jQuery('', { + 'title': 'Filter Markups', + 'class': 'toolButton inactive', + 'src': 'images/filter.svg' + }); + tool.append(this.filterbutton); // Filter Button - /* - * Ganesh - * Mootools to Jquery for creation of toolbar buttons - */ + this.analyticsbutton = jQuery('', { + 'title': 'Image Analysis', + 'class': 'toolButton', + 'src': 'images/analyze.png' - this.homebutton = jQuery('', { - 'data-toggle': 'tooltip', 'data-placement': 'bottom', - src: 'images/ic_home_white_24px.svg', - class: 'toolButton firstToolButtonSpace', - title: 'QuIP Home' - }); - tool.append(this.homebutton); - - this.lymphbutton = jQuery('', { - 'data-toggle': 'tooltip', - 'data-placement': 'bottom', - 'title': 'Lymphocyte & Plasma Cell Annotation App', - 'class': 'toolButton', - 'src': 'images/Heatmap.svg' - }); + }); + tool.append(this.analyticsbutton); - tool.append(this.lymphbutton); // Lymphocyte Button - this.spacer1 = jQuery('', { - 'class': 'spacerButton', - 'src': 'images/spacer.svg' - }); - tool.append(this.spacer1); - - /*a link to segment curation application with this composite button */ - this.compositebutton = jQuery('', { - 'data-toggle': 'tooltip', - 'data-placement': 'bottom', - title: 'Segment Curation App', - class: 'toolButton', - src: 'images/composite.png', - id: 'gotocompositebutton' - }); - tool.append(this.compositebutton); + /* Annotation tools (re-add, comment) */ + this.rectbutton = jQuery('', { + 'data-toggle': 'tooltip', + 'data-placement': 'bottom', + title: 'Draw Rectangle', + id: 'drawRectangle', + class: 'toolButton firstToolButtonSpace', + src: 'images/rect.svg' + }); + tool.append(this.rectbutton); + this.pencilbutton = jQuery('', { + 'data-toggle': 'tooltip', + 'data-placement': 'bottom', + 'title': 'Draw Freeline', + 'class': 'toolButton', + 'src': 'images/pencil.svg' + }); + tool.append(this.pencilbutton); // Pencil Tool + + this.rectbutton.on('click', function () { + this.mode = 'rect'; + this.annotools.mode = 'rect'; + this.annotools.drawMarkups() + // alert("Creation of markups is disabled on QuIP") + }.bind(this)); + + this.pencilbutton.on('click', function () { + this.annotools.mode = 'pencil'; + jQuery('html,body').css('cursor', 'crosshair'); + this.annotools.drawMarkups(); + }.bind(this)); + + this.sharebutton = jQuery('', { + 'data-toggle': 'tooltip', + 'data-placement': 'bottom', + 'title': 'Share Current View', + 'class': 'toolButton', + 'src': 'images/share.svg' + }); - this.rectbutton = jQuery('', { - 'data-toggle': 'tooltip', - 'data-placement': 'bottom', - title: 'Draw Rectangle', - id: 'drawRectangle', - class: 'toolButton firstToolButtonSpace', - src: 'images/rect.svg' - }); - //tool.append(this.rectbutton) - - this.ellipsebutton = jQuery('', { - 'data-toggle': 'tooltip', - 'data-placement': 'bottom', - 'title': 'Draw Ellipse', - 'class': 'toolButton', - 'src': 'images/ellipse.svg' - }); - //tool.append(this.ellipsebutton) - - this.pencilbutton = jQuery('', { - 'data-toggle': 'tooltip', - 'data-placement': 'bottom', - 'title': 'Draw Freeline', - 'class': 'toolButton', - 'src': 'images/pencil.svg' - }); - //tool.append(this.pencilbutton) // Pencil Tool - - this.measurebutton = jQuery('', { - 'data-toggle': 'tooltip', - 'data-placement': 'bottom', - 'title': 'Measurement Tool', - 'class': 'toolButton', - 'src': 'images/measure.svg' - }); - // tool.append(this.measurebutton) + tool.append(this.sharebutton); + this.magnifierButton = jQuery('', { + 'data-toggle': 'tooltip', + 'data-placement': 'bottom', + 'title': 'Toggle Spyglass', + 'class': 'toolButton', + 'src': 'images/SpyGlass.svg', + 'id': 'spyglass_toolbar_button' + }); + // default invisible + this.magnifierButton.css("display", "none"); + tool.append(this.magnifierButton); + // it's ready + var event = new Event("magnifier-button-loaded"); + document.dispatchEvent(event); + + // side split button + this.sidesplitButton = jQuery('', { + 'data-toggle': 'tooltip', + 'data-placement': 'bottom', + 'title': 'Toggle SideSplit', + 'class': 'toolButton', + 'src': 'images/SpyGlass.svg', + 'id': 'sidesplit_toolbar_button' + }); + tool.append(this.sidesplitButton); + this.sidesplitButton.on('click', function(){ + var event = new Event("sidesplit"); + document.dispatchEvent(event); + }); - this.spacer2 = jQuery('', { - 'class': 'spacerButton', - 'src': 'images/spacer.svg' - }); - tool.append(this.spacer2); - - this.filterbutton = jQuery('', { - 'data-toggle': 'tooltip', - 'data-placement': 'bottom', - 'title': 'Filter Markups', - 'class': 'toolButton firstToolButtonSpace', - 'src': 'images/filter.svg' - }); - tool.append(this.filterbutton); // Filter Button + /* + * Event handlers for toolbar buttons + */ + this.homebutton.on('click', function () { + window.location.href = "/select.php"; + }.bind(this)); + + /* + this.lymphbutton.on('click', function () { + var tissueId = this.iid; + window.location.href = "/camicroscope/osdCamicroscope_Lymph.php?tissueId=" + tissueId; + }.bind(this)) + */ + + this.lymphbutton.on('click', function () { + var tissueId = this.iid; + var x1 = annotool.imagingHelper._viewportOrigin['x']; + var y1 = annotool.imagingHelper._viewportOrigin['y']; + var x2 = x1 + annotool.imagingHelper._viewportWidth; + var y2 = y1 + annotool.imagingHelper._viewportHeight; + var zoom = viewer.viewport.getZoom(); + + var width, height; + //get image width and height + var url = 'api/Data/getImageInfoByCaseID.php?case_id=' + tissueId; + //console.log(url); + jQuery.get(url, function (data) { + //console.log(data); + try { + this_image = JSON.parse(data); + width = this_image[0].width; + height = this_image[0].height; + var x = parseInt(((x1 + x2) / 2.0) * width); + var y = parseInt(((y1 + y2) / 2.0) * height); + window.location.href = "/camicroscope/osdCamicroscope_Lymph.php?appid=lymph&tissueId=" + tissueId + "&x=" + x + "&y=" + y + "&zoom=" + zoom; + } catch (error) { + window.location.href = "/camicroscope/osdCamicroscope_Lymph.php?appid=lymph&tissueId=" + tissueId; + } + }) + }.bind(this)); +/* + this.qualitybutton.on('click', function () { + var tissueId = this.iid; + var x1 = annotool.imagingHelper._viewportOrigin['x']; + var y1 = annotool.imagingHelper._viewportOrigin['y']; + var x2 = x1 + annotool.imagingHelper._viewportWidth; + var y2 = y1 + annotool.imagingHelper._viewportHeight; + var zoom = viewer.viewport.getZoom(); + + var width, height; + //get image width and height + var url = 'api/Data/getImageInfoByCaseID.php?case_id=' + tissueId; + //console.log(url); + jQuery.get(url, function (data) { + //console.log(data); + try { + this_image = JSON.parse(data); + width = this_image[0].width; + height = this_image[0].height; + var x = parseInt(((x1 + x2) / 2.0) * width); + var y = parseInt(((y1 + y2) / 2.0) * height); + window.location.href = "/camicroscope/osdCamicroscope_Lymph.php?appid=qualheat&tissueId=" + tissueId + "&x=" + x + "&y=" + y + "&zoom=" + zoom; + } catch (error) { + window.location.href = "/camicroscope/osdCamicroscope_Lymph.php?appid=qualheat&tissueId=" + tissueId; + } + }) + }.bind(this)); +*/ + this.sharebutton.on('click', function () { + // update the url + LinkRequest(); + window.prompt("Share this link", window.location.href + "&" + camic_state.prefix + "=" + camic_state.encode(camic_state.vals)); + }.bind(this)); + + + this.filterbutton.on('click', function () { + this.toggleAlgorithmSelector() + // this.removeMouseEvents() + // this.promptForAnnotation(null, "filter", this, null) + }.bind(this)); + this.compositebutton.on('click', function () { + this.mode = 'composite'; + var tissueId = this.iid; + //window.location.href = "/camicroscope/osdCamicroscope_sc.php?tissueId="+tissueId; + + var x1 = annotool.imagingHelper._viewportOrigin['x']; + var y1 = annotool.imagingHelper._viewportOrigin['y']; + var x2 = x1 + annotool.imagingHelper._viewportWidth; + var y2 = y1 + annotool.imagingHelper._viewportHeight; + var zoom = viewer.viewport.getZoom(); + //zoom = parseInt(zoom); + if (zoom < 1.0) { + zoom = 1.0; + } + var width, height; + //get image width and height + var url = 'api/Data/getImageInfoByCaseID.php?case_id=' + tissueId; + //console.log(url); + jQuery.get(url, function (data) { + //console.log(data); + try { + this_image = JSON.parse(data); + width = this_image[0].width; + height = this_image[0].height; + var x = parseInt(((x1 + x2) / 2.0) * width); + var y = parseInt(((y1 + y2) / 2.0) * height); + window.location.href = "/camicroscope/osdCamicroscope_sc.php?tissueId=" + tissueId + "&cancerType=quip&x=" + x + "&y=" + y + "&zoom=" + zoom; + } catch (error) { + window.location.href = "/camicroscope/osdCamicroscope_sc.php?tissueId=" + tissueId; + } + }) + + }.bind(this)); + + this.analyticsbutton.on('click', function () { + this.annotools.createWorkOrder() + }.bind(this)); + + var toolButtons = jQuery('.toolButton'); + toolButtons.each(function () { + jQuery(this).on({ + 'mouseenter': function () { + // highlight button + this.addClass('selected') + }, + 'mouseleave': function () { + // un-highlight button + this.removeClass('selected') + } + }) + }) + } - this.hidebutton = jQuery('', { - 'data-toggle': 'tooltip', - 'data-placement': 'bottom', - 'title': 'Show/Hide Markups', - 'class': 'toolButton', - 'src': 'images/hide.svg' - }); - //tool.append(this.hidebutton) - - this.fullDownloadButton = jQuery('', { - 'data-toggle': 'tooltip', - 'data-placement': 'bottom', - 'title': 'Download All Markups (Coming Soon)', - 'class': 'toolButton', - 'src': 'images/fullDownload.svg' + this.ajaxBusy = jQuery('', { + 'class': 'colorMapButton', + 'id': 'ajaxBusy', + 'style': 'scale(0.5, 1)', + 'src': 'images/progress_bar.gif' }); - //tool.append(this.fullDownloadButton) - this.spacer1 = jQuery('', { - 'class': 'spacerButton', - 'src': 'images/spacer.svg' - }); - tool.append(this.spacer1); - - this.analyticsbutton = jQuery('', { - 'data-toggle': 'tooltip', - 'data-placement': 'bottom', - 'title': 'Image Analysis', - 'class': 'toolButton', - 'src': 'images/analyze.png' + tool.append(this.ajaxBusy); + this.ajaxBusy.hide(); + this.titleButton = jQuery('

', { + 'class': 'titleButton', + 'id': 'titleButton', + 'text': 'caMicroscope' }); - tool.append(this.analyticsbutton); - - this.filterImgButton = jQuery('', { - 'data-toggle': 'tooltip', - 'data-placement': 'bottom', - 'title': 'View Results', - 'class': 'toolButton', - 'src': 'images/insta.png' - }); - //tool.append(this.filterImgButton) - - this.bookmarkButton = jQuery('', { - 'data-toggle': 'tooltip', - 'data-placement': 'bottom', - 'title': 'Bookmark/Share current state', - 'class': 'toolButton', - 'src': 'images/ic_insert_link_white_24dp_1x.png' - }); - //tool.append(this.bookmarkButton) - - this.partialDownloadButton = jQuery('', { - 'data-toggle': 'tooltip', - 'data-placement': 'bottom', - 'title': 'Download Partial Markups (Coming Soon)', - 'class': 'toolButton', - 'src': 'images/partDownload.svg' - }); - // tool.append(this.partialDownloadButton) //Partial Download + tool.append(this.titleButton); - /* - * Event handlers for toolbar buttons - */ - this.homebutton.on('click', function () { - window.location.href = "/select.php"; + this.iidbutton = jQuery('

', { + 'class': 'iidButton', + 'text': 'Display ID: ' + this.displayId }); + tool.append(this.iidbutton); - /* - this.lymphbutton.on('click', function () { - var tissueId = this.iid; - window.location.href = "/camicroscope/osdCamicroscope_Lymph.php?tissueId=" + tissueId; - }.bind(this)) - */ - - this.lymphbutton.on('click', function () { - var tissueId = this.iid; - var x1 = annotool.imagingHelper._viewportOrigin['x']; - var y1 = annotool.imagingHelper._viewportOrigin['y']; - var x2 = x1 + annotool.imagingHelper._viewportWidth; - var y2 = y1 + annotool.imagingHelper._viewportHeight; - var zoom = viewer.viewport.getZoom(); - - var width, height; - //get image width and height - var url = 'api/Data/getImageInfoByCaseID.php?case_id=' + tissueId; - //console.log(url); - jQuery.get(url, function (data) { - //console.log(data); - try { - this_image = JSON.parse(data); - width = this_image[0].width; - height = this_image[0].height; - var x = parseInt(((x1 + x2) / 2.0) * width); - var y = parseInt(((y1 + y2) / 2.0) * height); - window.location.href = "/camicroscope/osdCamicroscope_Lymph.php?tissueId=" + tissueId + "&x=" + x + "&y=" + y + "&zoom=" + zoom; - } catch (error) { - window.location.href = "/camicroscope/osdCamicroscope_Lymph.php?tissueId=" + tissueId; - } - }) - }.bind(this)) - - this.compositebutton.on('click', function () { - this.mode = 'composite'; - var tissueId = this.iid; - //window.location.href = "/camicroscope/osdCamicroscope_sc.php?tissueId="+tissueId; - - var x1 = annotool.imagingHelper._viewportOrigin['x']; - var y1 = annotool.imagingHelper._viewportOrigin['y']; - var x2 = x1 + annotool.imagingHelper._viewportWidth; - var y2 = y1 + annotool.imagingHelper._viewportHeight; - var zoom = viewer.viewport.getZoom(); - //zoom = parseInt(zoom); - if (zoom < 1.0) - { - zoom = 1.0; - } - var width, height; - //get image width and height - var url = 'api/Data/getImageInfoByCaseID.php?case_id=' + tissueId; - //console.log(url); - jQuery.get(url, function (data) { - //console.log(data); - try { - this_image = JSON.parse(data); - width = this_image[0].width; - height = this_image[0].height; - var x = parseInt(((x1 + x2) / 2.0) * width); - var y = parseInt(((y1 + y2) / 2.0) * height); - window.location.href = "/camicroscope/osdCamicroscope_sc.php?tissueId=" + tissueId + "&cancerType=quip&x=" + x + "&y=" + y + "&zoom=" + zoom; - } catch (error) { - window.location.href = "/camicroscope/osdCamicroscope_sc.php?tissueId=" + tissueId; - } - }) - }.bind(this)) - - - this.rectbutton.on('click', function () { - this.mode = 'rect' - this.annotools.mode = 'rect' - this.annotools.drawMarkups() - // alert("Creation of markups is disabled on QuIP") - }.bind(this)) - - this.bookmarkButton.on('click', function () { - console.log('bookmark') - - /* Get ViewPort */ - var bounds = viewer.viewport.getBounds() - console.log(bounds) - - /* Get Filters */ - var filters = [] - jQuery('#selected li').each(function () { - var id = this.id - var filter = hashTable[id] - // filters.push(filter.generatedFilter.getFilter()) - // console.log(filter) - var f = {} - var filterName = filter.name - var filterVal = filter.generatedFilter.getParams() - f.name = filterName - f.value = filterVal - filters.push(f) - // sync &= filter.generatedFilter.sync - }) - console.log(filters) - - var state = { - 'state': { - 'filters': filters, - 'viewport': bounds, - 'pan': viewer.viewport.getCenter(), - 'zoom': viewer.viewport.getZoom(), - 'tissueId': this.annotools.iid - } - } - console.log(state) - // var bookmarkURLDiv = jQuery.create('

').addClass('bookmarkURLDiv') - var bookmarkURLDiv = jQuery('#bookmarkURLDiv') - bookmarkURLDiv.html('') - var input = jQuery('') - var submit = jQuery('"; - else if (alt) - content += ""; - - content += ""; - content +="
"; - - var cancel = function () { - jQuery('#panel').hide('slide') - } - - panel.html(content); - - jQuery("#cancelPanel").click(function(){cancel();}); - - if(ctrl){ // Ctrl key for deletion of human generated annotation - jQuery("#deleteAnnot").click(function(e) { - //$("#confirmDelete").css( - //console.log(data.provenance.analysis.source); - if(data.provenance.analysis.source == "human"){ - jQuery("#confirmDeleteButton").click(function(){ - var secret = jQuery("#deleteSecret").val(); - var payload = { - "id": id, - "secret": secret + console.log(data); + + var features = []; + var properties = {}; + var algorithm = ""; + var coordinates = []; + + try { + if (data.properties.scalar_features) + features = data.properties.scalar_features[0].nv; + + properties = data.properties.annotations; + algorithm = data.algorithm; + coordinates = data.geometry.coordinates[0]; + + } catch (e) { + console.log(e); + } + + for (var i in properties) { + if (i == "secret") { + + } else { + var line = "
" + i + ": " + properties[i] + "
"; + content += line; } - - jQuery.ajax({ - url: 'api/Data/getProperties.php?id='+id, - type: 'DELETE', - data:(payload), - success: function(data){ - console.log(data); - jQuery("#panel").hide("slide"); - self.getMultiAnnot(); - } - }); - }); - } else { - alert("Can't delete computer generated segments"); } - }) - }; - - if (alt){ //new code go here to handle Alt key for featureScape view - if(data.provenance.analysis.source == "human" || 1){ - jQuery("#featureScape").click(function(){ - - var execution_id= algorithm_id; - var this_case_id = case_id; - var this_cancerType = cancerType ; - var x_min= coordinates[0][0]; - var y_min= coordinates[0][1]; - var x_max= coordinates[2][0]; - var y_max= coordinates[2][1]; - //var randval = Math.random(); - var randval = 0.0001; - var featureScape_url=""; - - //var github_url="http://sbu-bmi.github.io/FeatureScapeApps/featurescape/?"; - //var osprey_url="http://osprey.bmi.stonybrook.edu:3000?"; - - var webhost_url="/featurescapeapps/featurescape/?"; - - //var findAPI_host="http://129.49.249.191"; - //var findAPI_port="4500"; - // var findAPI_url=findAPI_host+":"+findAPI_port+"?"; - - //var findAPI_url=findAPIConfig.findAPI+":"+findAPIConfig.port+"?"; - var findAPI_url = findAPIConfig.findAPI + "?"; - - var mongodb_query="limit=1000&find={"; - mongodb_query +="\"provenance.analysis.source\":\"computer\","; - mongodb_query+="\"randval\":{\"$gte\":"+randval+"},"; - mongodb_query+="\"provenance.analysis.execution_id\":\""+execution_id+"\","; - mongodb_query+="\"provenance.image.case_id\":\""+this_case_id+"\","; - mongodb_query+="\"x\":{\"$gte\":"+x_min+",\"$lte\":"+x_max+"},"; - mongodb_query+="\"y\":{\"$gte\":"+y_min+",\"$lte\":"+y_max+"}"; - mongodb_query+="}&db=quip"+"&c="+this_cancerType; - - //featureScape_url=github_url+osprey_url+mongodb_query; - featureScape_url=webhost_url+findAPI_url+mongodb_query; - - console.log(featureScape_url); - window.open(featureScape_url,'_blank'); - jQuery("#panel").hide("slide"); - self.getMultiAnnot(); - }); - } else { - alert("Can't view the featureScape of computer generated segments"); - } - } ;//end of new code - + for (var i = 0; i < features.length; i++) { + var feature = features[i]; + var line = "
" + feature.name + "
" + feature.value + "
"; + content += line; + } + + if (ctrl) + content += ""; + else if (alt) + content += ""; + + content += ""; + content += ""; + + var cancel = function () { + jQuery('#panel').hide('slide') + }; + + panel.html(content); + + jQuery("#cancelPanel").click(function () { + cancel(); + }); + + if (ctrl) { // Ctrl key for deletion of human generated annotation + jQuery("#deleteAnnot").click(function (e) { + //$("#confirmDelete").css( + //console.log(data.provenance.analysis.source); + if (data.provenance.analysis.source == "human") { + jQuery("#confirmDeleteButton").click(function () { + var secret = jQuery("#deleteSecret").val(); + var payload = { + "id": id, + "secret": secret + }; + + jQuery.ajax({ + url: 'api/Data/getPropertiesClone.php?id=' + id, + type: 'DELETE', + data: (payload), + success: function (data) { + console.log(data); + jQuery("#panel").hide("slide"); + self.getMultiAnnot(); + } + }); + }); + } else { + alert("Can't delete computer generated segments"); + } + }) + } + if (alt) { //new code go here to handle Alt key for featureScape view + if (data.provenance.analysis.source == "human" || 1) { + jQuery("#featureScape").click(function () { + + var execution_id = algorithm_id; + var this_case_id = case_id; + var this_cancerType = cancerType; + var x_min = coordinates[0][0]; + var y_min = coordinates[0][1]; + var x_max = coordinates[2][0]; + var y_max = coordinates[2][1]; + //var randval = Math.random(); + var randval = 0.0001; + var featureScape_url = ""; + + //var github_url="http://sbu-bmi.github.io/FeatureScapeApps/featurescape/?"; + //var osprey_url="http://osprey.bmi.stonybrook.edu:3000?"; + + var webhost_url = "/featurescapeapps/featurescape/?"; + + //var findAPI_host="http://129.49.249.191"; + //var findAPI_port="4500"; + // var findAPI_url=findAPI_host+":"+findAPI_port+"?"; + + //var findAPI_url=findAPIConfig.findAPI+":"+findAPIConfig.port+"?"; + var findAPI_url = findAPIConfig.findAPI + "?"; + + var mongodb_query = "limit=1000&find={"; + mongodb_query += "\"provenance.analysis.source\":\"computer\","; + mongodb_query += "\"randval\":{\"$gte\":" + randval + "},"; + mongodb_query += "\"provenance.analysis.execution_id\":\"" + execution_id + "\","; + mongodb_query += "\"provenance.image.case_id\":\"" + this_case_id + "\","; + mongodb_query += "\"x\":{\"$gte\":" + x_min + ",\"$lte\":" + x_max + "},"; + mongodb_query += "\"y\":{\"$gte\":" + y_min + ",\"$lte\":" + y_max + "}"; + mongodb_query += "}&db=quip" + "&c=" + this_cancerType; + + //featureScape_url=github_url+osprey_url+mongodb_query; + featureScape_url = webhost_url + findAPI_url + mongodb_query; + + console.log(featureScape_url); + window.open(featureScape_url, '_blank'); + jQuery("#panel").hide("slide"); + self.getMultiAnnot(); + }); + } else { + alert("Can't view the featureScape of computer generated segments"); + } + } + //end of new code }); - - }) + }) - /* - jQuery('.annotationsvg').mousedown(function (event) { - - switch (event.which) { - case 3: + /* + jQuery('.annotationsvg').mousedown(function (event) { + switch (event.which) { + case 3: - var panel = jQuery('#panel').show('slide') - panel.html(''); - var id = event.target.id - var url = "api/Data/getProperties.php?id="+id; - var content = "

Annotation Details

" - + "
"; + var panel = jQuery('#panel').show('slide') + panel.html(''); - jQuery.get(url, function(data){ - - var data = JSON.parse(data)[0]; - var properties = data.properties.annotations; - for(var i in properties){ - - if(i == "secret"){ + var id = event.target.id + var url = "api/Data/getProperties.php?id="+id; + var content = "

Annotation Details

" + + "
"; + + jQuery.get(url, function(data){ + + var data = JSON.parse(data)[0]; + var properties = data.properties.annotations; + for(var i in properties){ + + if(i == "secret"){ + + } else { + var line = "
"+i+": " + properties[i]+"
"; + content+=line; + } - } else { - var line = "
"+i+": " + properties[i]+"
"; - content+=line; } - - } - content += ""; - content +="
"; - var cancel = function () { - - jQuery('#panel').hide('slide') + content += ""; + content +="
"; + var cancel = function () { - } + jQuery('#panel').hide('slide') - panel.html(content); + } + panel.html(content); - jQuery("#cancelPanel").click(function(){cancel();}); + jQuery("#cancelPanel").click(function(){cancel();}); - }); - // jQuery("#panel").hide("slide") - break - } - }) - */ -} + + }); + // jQuery("#panel").hide("slide") + break + } + }) + */ +}; annotools.prototype.displayGeoAnnots = function () { - var geoJSONs = this.annotations - if (this.annotVisible) { - // var renderStartTime = performance.now() - this.generateSVG(geoJSONs) - // var renderEndTime = performance.now() - var renderStartTime = 9 - var renderEndTime = 23 - } -} + var geoJSONs = this.annotations; // polygon objects + if (this.annotVisible) { + // var renderStartTime = performance.now() + this.generateSVG(geoJSONs); + // var renderEndTime = performance.now() + var renderStartTime = 9; + var renderEndTime = 23 + } +}; diff --git a/js/annotationtools/osdAnnotationTools.js b/js/annotationtools/osdAnnotationTools.js index 2188674af..dbe2afd91 100644 --- a/js/annotationtools/osdAnnotationTools.js +++ b/js/annotationtools/osdAnnotationTools.js @@ -1,6 +1,5 @@ /* - Copyright (C) 2012 Shaohuan Li , Ashish Sharma - This file is part of Biomedical Image Viewer developed under the Google of Summer of Code 2012 program. + This file is part of caMicroscope Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -9,6 +8,7 @@ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ +console.log("osdAnnotationTools.js"); /** * User-selected ROI. @@ -35,20 +35,22 @@ var annotools = function (options) { this.color = options.color || 'lime'; // Default Annotation Color this.iidDecoded = decodeURI(options.iid); - this.canvas = options.canvas; // The canvas Element that The Use will be drawing annotations on. + this.canvas = options.canvas; // The node id of the canvas Element to draw annotations on this.iid = options.iid || null; // The Image ID this.annotVisible = true; // The Annotations are Set to be visible at the First Loading this.mode = 'default'; // The Mode is Set to Default - + this.user_email = options.user_email; this.viewer = options.viewer; this.imagingHelper = this.viewer.imagingHelper; this.mpp = options.mpp; this.mppx = parseFloat(this.mpp['mpp-x']); this.mppy = parseFloat(this.mpp['mpp-y']); + this.markupid = options.markupid || "markups"; this.x1 = 0.0; this.x2 = 1.0; this.y1 = 0.0; this.y2 = 1.0; + this.container = document.getElementById(this.viewer.id).childNodes[0]; this.annotationHandler = options.annotationHandler || new AnnotoolsOpenSeadragonHandler(); @@ -61,7 +63,7 @@ var annotools = function (options) { }.bind(this)); this.viewer.addHandler('animation-start', function (event) { - var markup_svg = document.getElementById('markups'); + var markup_svg = document.getElementById(this.markupid); if (markup_svg) { // console.log("destroying") markup_svg.destroy(); @@ -139,7 +141,7 @@ var annotools = function (options) { annotools.prototype.destroyMarkups = function (viewer) { // console.log("Destroy markups"); - var markup_svg = document.getElementById('markups'); + var markup_svg = document.getElementById(this.markupid); if (markup_svg) { // console.log("destroying") markup_svg.destroy(); @@ -149,7 +151,7 @@ annotools.prototype.destroyMarkups = function (viewer) { /** * Rendering by execution ids - * Same as getMultiAnnot?? + * * @param algorithms */ annotools.prototype.renderByExecutionId = function (algorithms) { @@ -194,31 +196,11 @@ annotools.prototype.renderByExecutionId = function (algorithms) { /** * Get multiple annotations - * Same as renderByExecutionId?? + * * @param viewer */ annotools.prototype.getMultiAnnot = function (viewer) { - // console.log("Get multiple annotations"); - // console.log("viewer", viewer); - - // console.log("ALGORITHM_LIST", ALGORITHM_LIST); - // console.log("SELECTED_ALGORITHM_LIST", SELECTED_ALGORITHM_LIST); - - SELECTED_ALGORITHM_LIST = SELECTED_ALGORITHM_LIST.sort(); - var algorithms = SELECTED_ALGORITHM_LIST; - - /* - if (jQuery('#tree').attr('algotree')) { - var selalgos = jQuery('#tree').fancytree('getTree').getSelectedNodes() - // console.log(selalgos) - for (i = 0; i < selalgos.length; i++) { - algorithms.push(selalgos[i].refKey) - // opa["Val" + (i + 1).toString()] = selalgos[i].refKey - } - } - */ - var self = this; this.x1 = this.imagingHelper._viewportOrigin['x']; this.y1 = this.imagingHelper._viewportOrigin['y']; @@ -234,12 +216,53 @@ annotools.prototype.getMultiAnnot = function (viewer) { var origin = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(0), this.imagingHelper.physicalToDataY(0)); var area = (max.x - origin.x) * (max.y - origin.y); + if (SELECTED_ALGORITHM_LIST.length) { + SELECTED_ALGORITHM_LIST = SELECTED_ALGORITHM_LIST.sort(); + var algorithms = SELECTED_ALGORITHM_LIST; + var myList = OVERLAY_LIST; + + self.fetchAnnots(area, algorithms, myList); + } else { + self.setupHandlers(); + self.destroyMarkups(); + // destroy canvas + } + +}; + +annotools.prototype.filterit = function (a, b) { + + var aa = []; + var bb = []; + for (var i = 0; i < b.length; i++) { + bb.push(b[i].execid); + + } + + // If we've already displayed the tiles + // remove it from the "todo" list. + for (var i = 0; i < a.length; i++) { + var idx = bb.indexOf(a[i]); + if (idx < 0) { + aa.push(a[i]); + + } + } + + return aa; +}; + +annotools.prototype.fetchAnnots = function (area, SELECTED_ALGORITHM_LIST, OVERLAY_LIST) { + var self = this; + var algorithms = self.filterit(SELECTED_ALGORITHM_LIST, OVERLAY_LIST); + //console.log("**** algorithms ****", algorithms); if (algorithms.length) { + this.toolBar.titleButton.hide(); this.toolBar.ajaxBusy.show(); - this.annotations = this.AnnotationStore.fetchAnnotations(this.x1, this.y1, this.x2, this.y2, area, algorithms, function (data) { - // console.log(data); + + this.annotations = this.AnnotationStore.fetchAnnotations(self.x1, self.y1, self.x2, self.y2, area, algorithms, function (data) { self.annotations = data; self.displayGeoAnnots(); self.setupHandlers(); @@ -247,6 +270,7 @@ annotools.prototype.getMultiAnnot = function (viewer) { self.toolBar.titleButton.show(); self.toolBar.ajaxBusy.hide(); }); + } else { self.setupHandlers(); self.destroyMarkups(); @@ -414,7 +438,7 @@ annotools.prototype.drawMarkups = function () { this.magnifyGlass.hide(); // Hide The Magnifying Tool // this.container = document.id(this.canvas) //Get The Canvas Container - this.container = document.getElementsByClassName(this.canvas)[0]; // Get The Canvas Container + //this.container = document.getElementsByClassName(this.canvas)[0]; // Get The Canvas Container // this.container = document.getElementById('container') //Get The Canvas Container if (this.container) { @@ -501,7 +525,7 @@ annotools.prototype.createWorkOrder = function () { this.magnifyGlass.hide(); // Hide The Magnifying Tool // this.container = document.id(this.canvas) //Get The Canvas Container - this.container = document.getElementsByClassName(this.canvas)[0]; // Get The Canvas Container + // this.container = document.getElementsByClassName(this.canvas)[0]; // Get The Canvas Container // this.container = document.getElementById('container') //Get The Canvas Container if (this.container) { @@ -963,7 +987,7 @@ analyze: function(ctx) { this.drawLayer.show(); //Show The Drawing Layer this.magnifyGlass.hide(); //Hide The Magnifying Tool this.container = document.getElementsByClassName(this.canvas)[0]; //Get The Canvas Container - + var left = parseInt(this.container.getLeft()), //Get The Container Location top = parseInt(this.container.offsetTop), width = parseInt(this.container.offsetWidth), @@ -972,18 +996,18 @@ analyze: function(ctx) { otop = top, owidth = width, oheight = height; - + if (left < 0) { left = 0; width = window.innerWidth - } - + } + //See Whether The Container is outside The Current ViewPort if (top < 0) { top = 0; height = window.innerHeight } - + //Recreate The CreateAnnotation Layer Because of The ViewPort Change Issue. this.drawLayer.set({ 'styles': { @@ -993,19 +1017,19 @@ analyze: function(ctx) { height: height } }); - + //Create Canvas on the CreateAnnotation Layer this.drawCanvas.set({ width: width, height: height }); - + //The canvas context var ctx = this.drawCanvas.getContext("2d"); var started = false; var min_x, min_y, max_x, max_y, w, h; var startPosition; - + this.drawCanvas.addEvent('mousedown', function (e) { started = true; startPosition = OpenSeadragon.getMousePosition(e.event); @@ -1348,7 +1372,7 @@ annotools.prototype.updateAnnot = function (annot) { this.showMessage('saved to the server') }.bind(this), onFailure: function (e) { - this.showMessage('Error Saving the Annotations,please check you saveAnnot funciton') + this.showMessage('Error Saving the Annotations,please check your saveAnnot function') }.bind(this) }).post({ 'iid': this.iid, @@ -1366,18 +1390,34 @@ annotools.prototype.saveAnnot = function (annotation) { // console.log("Saving annotation"); // console.log("annotation", annotation) + region_type = annotation.properties.annotations.region; + //execution_id=annotation.provenance.analysis.execution_id; + var user = annotool.user; + if (region_type == "Tumor") { + var execution_id = user + "_Tumor_Region"; + annotation.provenance.analysis.execution_id = execution_id; + } + if (region_type == "Non_Tumor") { + annotation.provenance.analysis.execution_id = user + "_Non_Tumor_Region"; + } + + var d = new Date(); + var current_time = d.toLocaleString(); + annotation.created_by = user; + annotation.created_on = current_time; + annotation.updated_by = ''; + annotation.updated_on = ''; jQuery.ajax({ 'type': 'POST', - url: 'api/Data/getAnnotSpatial.php', + url: 'api/Data/getAnnotSpatial_sc.php', data: annotation, success: function (res, err) { // console.log("response: ") console.log(res); console.log(err); - console.log('successfully posted') } - }) + }); }; @@ -2032,7 +2072,7 @@ annotools.prototype.saveState = function () { this.showMessage('saved to the server') }.bind(this), onFailure: function (e) { - this.showMessage('Error Saving the state,please check you saveState funciton') + this.showMessage('Error Saving the state,please check your saveState function') }.bind(this) }).post({ 'iid': this.iid, @@ -2695,7 +2735,6 @@ annotools.prototype.promptForWorkOrder = function (newAnnot, mode, annotools, ct // End of Text input code // - // TODO: remove hardcoded vars. var width = 48002; var height = 35558; @@ -2745,7 +2784,6 @@ annotools.prototype.promptForWorkOrder = function (newAnnot, mode, annotools, ct //var execution_id = jQuery('#order-execution_id').val() var notes = jQuery('#order-notes').val(); - // TODO: remove if statement if (iid === 'TCGA-06-0148-01Z-00-DX1') { width = 26001; height = 27968 @@ -2861,7 +2899,7 @@ annotools.prototype.promptForWorkOrder = function (newAnnot, mode, annotools, ct * @param cb */ function pollOrder(id, cb) { - // console.log("Poll Order"); + //console.log("pollOrder"); jQuery.get("api/Data/workOrder.php?id=" + id, function (data) { @@ -2904,9 +2942,12 @@ annotools.prototype.promptForAnnotation = function (newAnnot, mode, annotools, c + '' ); - jQuery.get('api/Data/retrieveTemplate.php', function (data) { + jQuery.get('api/Data/retrieveTemplate.php?app_name=tumor_markup', function (data) { + console.log("data", data); var schema = JSON.parse(data); schema = JSON.parse(schema)[0]; + //region_list=schema.region.enum; + //schema.region.enum=["Tumor","Non_Tumor"]; // console.log("schema", schema); // console.log("retrieved template") var formSchema = { diff --git a/js/annotationtools_sc/AnnotationStore_sc.js b/js/annotationtools_sc/AnnotationStore_sc.js index 01be19e55..1e878060d 100644 --- a/js/annotationtools_sc/AnnotationStore_sc.js +++ b/js/annotationtools_sc/AnnotationStore_sc.js @@ -65,7 +65,7 @@ AnnotationStore.prototype.fetchAnnotations = function(x1,y1,x2,y2, footprint, al var midX = x2; var midY = y2; - //dispaly composite_input annotation while in low scale viewport + //display composite_input annotation while in low scale viewport var isCompositeAnnotationOnly= true; var isNonCompositeAnnotationOnly=true; var algorithms_computer= []; diff --git a/js/annotationtools_sc/ToolBar_sc.js b/js/annotationtools_sc/ToolBar_sc.js index 28118ad4b..5ac4d2b59 100644 --- a/js/annotationtools_sc/ToolBar_sc.js +++ b/js/annotationtools_sc/ToolBar_sc.js @@ -1,624 +1,442 @@ - -var ToolBar = function (element, options) { - // console.log(options) - this.annotools = options.annotool - // console.log(this.annotools) - this.FilterTools = options.FilterTools - this.source = element // The Tool Source Element - this.top = options.top || '0px' - this.left = options.left || '150px' // The Tool Location - this.height = options.height || '30px' - this.width = options.width || '270px' - this.zindex = options.zindex || '100' // To Make Sure The Tool Appears in the Front - - this.iid = options.iid || null; - this.cancerType = options.cancerType; - this.annotationActive = isAnnotationActive() -} - - -ToolBar.prototype.showMessage = function (msg) { - console.log(msg) -} - -ToolBar.prototype.algorithmSelector = function () { - var self = this - var ftree - xxx = [] -} - -//var available_colors = ['lime', 'red', 'blue', 'orange','silver','maroon','aqua','fuchsia','green','black'] -var available_colors = ['#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f','#ff7f00','#cab2d6','#6a3d9a','#ffff99','#b15928']; - -var algorithm_color = {} - -function goodalgo (data, status) { - //console.log("goodalgo data is: "+data); - // console.log("data.length is: "+data.length) - - var blob = [] - for (i = 0;i < data.length;i++) { - var n = {} - //console.log(data[i]) - data[i].title=data[i].provenance.analysis_execution_id; - n.title = "
" + data[i].title - n.key = i.toString() - n.refKey = data[i].provenance.analysis_execution_id - n.color = available_colors[i%available_colors.length] - algorithm_color[data[i].provenance.analysis_execution_id] = available_colors[i%available_colors.length]; - blob.push(n) - } - - console.log("blob is: "+blob); - - ftree = jQuery('#tree').fancytree({ - source: [{ - title: 'Algorithms', key: '1', folder: true, - children: blob, - expanded: true - }], - minExpandLevel: 1, // 1: root node is not collapsible - activeVisible: true, // Make sure, active nodes are visible (expanded). - aria: false, // Enable WAI-ARIA support. - autoActivate: true, // Automatically activate a node when it is focused (using keys). - autoCollapse: false, // Automatically collapse all siblings, when a node is expanded. - autoScroll: false, // Automatically scroll nodes into visible area. - clickFolderMode: 4, // 1:activate, 2:expand, 3:activate and expand, 4:activate (dblclick expands) - checkbox: true, // Show checkboxes. - debugLevel: 2, // 0:quiet, 1:normal, 2:debug - disabled: false, // Disable control - focusOnSelect: false, // Set focus when node is checked by a mouse click - generateIds: false, // Generate id attributes like - idPrefix: 'ft_', // Used to generate node id´s like . - icons: true, // Display node icons. - keyboard: true, // Support keyboard navigation. - keyPathSeparator: '/', // Used by node.getKeyPath() and tree.loadKeyPath(). - minExpandLevel: 1, // 1: root node is not collapsible - quicksearch: false, // Navigate to next node by typing the first letters. - selectMode: 2, // 1:single, 2:multi, 3:multi-hier - tabbable: true, // Whole tree behaves as one single control - titlesTabbable: false, // Node titles can receive keyboard focus - beforeSelect: function (event, data) { - // A node is about to be selected: prevent this for folders: - if (data.node.isFolder()) { - return false - } - }, - select: function (event, data) { - jQuery('#tree').attr('algotree', true) - var node = data.node - - console.log('!SELECTED NODE : ' + node.title) - targetType = data.targetType - annotool.getMultiAnnot() - } - }) -} - -/* -ToolBar.prototype.toggleAlgorithmSelector = function () { - if (!jQuery('#algosel').attr('eb')) { - jQuery('#algosel').attr('eb', true) - // console.log("initializing...") - jQuery('#algosel').css({ - 'width': '300px', - 'zIndex': 199, - 'visibility': 'hidden' - }) - jQuery('#algosel').on('mousedown', function (e) { - jQuery(this).addClass('draggable').parents().on('mousemove', function (e) { - jQuery('.draggable').offset({ - top: e.pageY - jQuery('.draggable').outerHeight() / 2, - left: e.pageX - jQuery('.draggable').outerWidth() / 2 - }).on('mouseup', function () { - jQuery(this).removeClass('draggable') - }) - }) - e.preventDefault() - }).on('mouseup', function () { - jQuery('.draggable').removeClass('draggable') - }) - } - if (jQuery('#algosel').css('visibility') == 'visible') { - jQuery('#algosel').css({ - 'visibility': 'hidden' - }) - } else { - jQuery('#algosel').css({ - 'visibility': 'visible' - }) - } - this.showMessage('Algorithm Selection Toggled') -} -*/ - - -var ALGORITHM_LIST = {}; -var SELECTED_ALGORITHM_LIST = []; -var SELECTED_ALGORITHM_KEYS = []; -var SELECTED_ALGORITHM_COLOR = {}; -var AlgorithmSelectorHidden = true; - -ToolBar.prototype.toggleAlgorithmSelector = function () { - var self = this; - console.log("toggleAlgorithmSelector"); - //jQuery("#panel").show("slide"); - var url = 'api/Data/getAlgorithmsForImage.php?iid=' + self.iid; - - var htmlStr = "

Select Algorithm

    "; - - jQuery.get(url, function (data) { - - d = JSON.parse(data) - - ALGORITHM_LIST = d; - - var tmp_algorithm_list=[]; - - for(var i=0; i < d.length; i++){ - tmp_algorithm_list[i]=d[i].provenance.analysis_execution_id; - } - - //tmp_algorithm_list = tmp_algorithm_list.sort(); - var algorithms_computer= []; - var algorithms_composite_input = []; - var algorithms_composite_dataset = []; - var algorithms_under = []; - var algorithms_over = []; - - var algorithm_number = tmp_algorithm_list.length; - if (algorithm_number >0) { - - for (i=0; i< algorithm_number; i++){ - var index_composite_input =tmp_algorithm_list[i].indexOf("composite_input"); - var index_composite_dataset =tmp_algorithm_list[i].indexOf("composite_dataset"); - var index_under =tmp_algorithm_list[i].indexOf("under_"); - var index_over =tmp_algorithm_list[i].indexOf("over_"); - - if(index_composite_input != -1){ - algorithms_composite_input.push(tmp_algorithm_list[i]); - } else if (index_composite_dataset != -1){ - algorithms_composite_dataset.push(tmp_algorithm_list[i]); - } else if (index_under != -1){ - algorithms_under.push(tmp_algorithm_list[i]); - } else if (index_over != -1){ - algorithms_over.push(tmp_algorithm_list[i]); - } else { - algorithms_computer.push(tmp_algorithm_list[i]); - } - } - algorithms_computer = algorithms_computer.sort(); - algorithms_under = algorithms_under.sort(); - algorithms_over =algorithms_over.sort(); - algorithms_composite_input=algorithms_composite_input.sort(); - algorithms_composite_dataset = algorithms_composite_dataset.sort(); - tmp_algorithm_list=algorithms_computer.concat(algorithms_under,algorithms_over,algorithms_composite_input,algorithms_composite_dataset); - } - - for(var i=0; i < tmp_algorithm_list.length; i++){ - //n.color = available_colors[i%7]; - //algorithm_color[d[i].provenance.analysis_execution_id] = available_colors[i%7] - algorithm_color[tmp_algorithm_list[i]] = available_colors[i%available_colors.length]; - SELECTED_ALGORITHM_COLOR[tmp_algorithm_list[i]]= available_colors[i%available_colors.length]; - htmlStr += "
  • "+tmp_algorithm_list[i] - + "
  • "; - } - - htmlStr +="

"; - - jQuery("#panel").html(htmlStr); - - jQuery("#algorithmList input[type=checkbox]").each(function() { - - var elem = jQuery(this) - var id = (this).value*1; - for(var i=0; i < SELECTED_ALGORITHM_KEYS.length; i++){ - if(SELECTED_ALGORITHM_KEYS[i] == (id)){ - - elem.prop('checked', true); - } - } - }); - - self.annotools.getMultiAnnot(); - - jQuery('#algorithmList input[type=checkbox]').change(function() { - console.log("change"); - SELECTED_ALGORITHM_LIST = []; - SELECTED_ALGORITHM_KEYS = []; - - jQuery("#algorithmList input:checked").each(function() { - SELECTED_ALGORITHM_LIST.push(tmp_algorithm_list[(this).value * 1]); - SELECTED_ALGORITHM_KEYS.push((this).value*1); - - console.log("tmp_algorithm_list is: "+tmp_algorithm_list); - - console.log("index value of array is: "+(this).value * 1); - }); - - console.log("SELECTED_ALGORITHM_LIST is: "+SELECTED_ALGORITHM_LIST); - console.log("SELECTED_ALGORITHM_KEYS is: "+SELECTED_ALGORITHM_KEYS); - self.annotools.getMultiAnnot(); - }) - - - - jQuery("#cancelAlgorithms").click(function(){ - jQuery("#panel").html(""); - jQuery("#panel").hide("slide"); - AlgorithmSelectorHidden = true; - }); - }); - - if(AlgorithmSelectorHidden == true){ - jQuery("#panel").show("slide"); - AlgorithmSelectorHidden = false; - } else { - jQuery("#panel").html(""); - jQuery("#panel").hide("slide"); - - AlgorithmSelectorHidden = true; - } - -} - - -ToolBar.prototype.setNormalMode = function() { - this.annotools.mode = 'normal'; - jQuery("canvas").css("cursor", "default"); - jQuery("#drawRectangleButton").removeClass('active'); - jQuery("#drawFreelineButton").removeClass('active'); - jQuery("#drawDotButton").removeClass("active"); // Dot Tool - jQuery("#mergeStep2Button").removeClass("active"); // merge Step2 Button - this.annotools.drawLayer.hide() - this.annotools.addMouseEvents() -} - -ToolBar.prototype.createButtons = function () { - // this.tool = jQ(this.source) - var tool = jQuery('#' + 'tool') // Temporary dom element while we clean up mootools - var self = this - - // Fetch algorithms for Image - jQuery(document).ready(function () { - // console.log(options) - - console.log("self.iid is: "+self.iid); - - jQuery.get('api/Data/getAlgorithmsForImage.php?iid=' + self.iid, function (data) { - d = JSON.parse(data); - // console.log("data before goodalgo is:"+data); - // console.log("d before goodalgo is:"+d); - goodalgo(d, null) - }) - - // console.log("here") - jQuery('#submitbtn').click(function () { - var selKeys = jQuery('#tree').fancytree('getTree').getSelectedNodes() - var param = '' - for (i = 0;i < selKeys.length;i++) { - param = param + '&Val' + (i + 1).toString() + '=' + selKeys[i].title - } - }) - }) - - tool.css({ - 'position': 'absolute', - 'left': this.left, - 'top': this.top, - 'width': this.width, - 'height': this.height, - 'z-index': this.zindex - }) - - tool.addClass('annotools') // Update Styles - // this.tool.makeDraggable(); //Make it Draggable. - - - if (this.annotationActive) { - /* - * Ganesh - * Mootools to Jquery for creation of toolbar buttons +/** + * TOOLBAR + * SEGMENTATION CURATION APP + */ +$.getScript('shared/ToolBar.js', function () { + + /** + * Create Buttons */ - - this.homebutton = jQuery('', { - title: 'caMicroscope Home', - class: 'toolButton firstToolButtonSpace inactive', - src: 'images/home.png', - id: 'gotohomebutton' - }) - tool.append(this.homebutton) - - this.spacer1 = jQuery('', { - 'class': 'spacerButton inactive', - 'src': 'images/spacer.svg' - }) - tool.append(this.spacer1) - - this.rectbutton = jQuery('', { - title: 'Draw Rectangle', - class: 'toolButton inactive', - src: 'images/rect.svg', - id: 'drawRectangleButton' - }) - //tool.append(this.rectbutton) - - - this.pencilbutton = jQuery('', { - 'title': 'Draw Freeline', - 'class': 'toolButton inactive', - 'src': 'images/pencil.svg', - 'id': 'drawFreelineButton' - }) - tool.append(this.pencilbutton) // Pencil Tool - - - this.mergebutton1 = jQuery('', { - 'title': 'Save ViewPort', - 'class': 'toolButton inactive', - 'src': 'images/merge1.png' - }) - tool.append(this.mergebutton1) // Merge step 1 - - this.mergebutton2 = jQuery('', { - 'title': 'Save Rectangle And Delete Annotation(s) Within This Area', - 'class': 'toolButton inactive', - 'src': 'images/rect.svg', - 'id': 'mergeStep2Button' - }) - tool.append(this.mergebutton2) // Merge step 2 - - this.spacer2 = jQuery('', { - 'class': 'spacerButton inactive', - 'src': 'images/spacer.svg' - }) - tool.append(this.spacer2) - - this.filterbutton = jQuery('', { - 'title': 'Filter Markups', - 'class': 'toolButton inactive', - 'src': 'images/filter.svg' - }) - tool.append(this.filterbutton) // Filter Button - - - this.measurebutton = jQuery('', { - 'title': 'Measurement Tool', - 'class': 'toolButton inactive', - 'src': 'images/measure.svg' - }) - // tool.append(this.measurebutton) - - this.spacer3 = jQuery('', { - 'class': 'spacerButton inactive', - 'src': 'images/spacer.svg' - }) - tool.append(this.spacer3) - - - this.mergebutton3 = jQuery('', { - 'title': 'Generate Composite Dataset', - 'class': 'toolButton inactive', - 'src': 'images/merge2.png', - 'id': 'mergeStep3Button' - }) - tool.append(this.mergebutton3) // Merge step 3 - - this.hidebutton = jQuery('', { - 'title': 'Show/Hide Markups', - 'class': 'toolButton inactive', - 'src': 'images/hide.svg' - }) - // tool.append(this.hidebutton) - - - this.spacer4 = jQuery('', { - 'class': 'spacerButton inactive', - 'src': 'images/spacer.svg' - }) - tool.append(this.spacer4) - - this.partialDownloadButton = jQuery('', { - 'title': 'Download Partial Markups (Coming Soon)', - 'class': 'toolButton inactive', - 'src': 'images/partDownload.svg' - }) - //tool.append(this.partialDownloadButton) //Partial Download - - this.spacer5 = jQuery('', { - 'class': 'spacerButton inactive', - 'src': 'images/spacer.svg' - }); - // tool.append(this.spacer5); - - this.dotToolButton = jQuery('', { - 'title': 'Dot Tool', - 'class': 'toolButton inactive', - 'src': 'images/analyze.png', - 'id': 'drawDotButton' - }); - // tool.append(this.dotToolButton); // Dot Tool - - - /* - * Event handlers on click for the buttons - */ - - this.homebutton.on('click', function () { - this.mode = 'home'; - var tissueId=annotool.iid; - var cancerType=annotool.cancerType; - //window.location.href = "/camicroscope/osdCamicroscope.php?tissueId="+tissueId+"&cancerType="+cancerType; - var x1 = annotool.imagingHelper._viewportOrigin['x']; - var y1 = annotool.imagingHelper._viewportOrigin['y']; - var x2 = x1 + annotool.imagingHelper._viewportWidth; - var y2 = y1 + annotool.imagingHelper._viewportHeight; - var zoom = viewer.viewport.getZoom(); - if (zoom<1.0) zoom=1.0; - var width,height; - //get image width and height - var url = 'api/Data/getImageInfoByCaseID.php?case_id=' + tissueId; - jQuery.get(url, function (data) { - //console.log(data); - try { - this_image = JSON.parse(data); - width = this_image[0].width; - height = this_image[0].height; - var x= parseInt(((x1+x2)/2.0)*width); - var y= parseInt(((y1+y2)/2.0)*height); - window.location.href = "/camicroscope/osdCamicroscope.php?tissueId="+tissueId+"&x="+x+"&y="+y+"&zoom="+zoom; - } catch (error){ - window.location.href = "/camicroscope/osdCamicroscope.php?tissueId="+tissueId; - } - }) - }.bind(this)) - - - this.rectbutton.on('click', function () { - //console.log(this.mode); - if(this.annotools.mode == 'rect'){ - this.setNormalMode(); - //this. - } else { - this.mode = 'rect' - this.annotools.mode = 'rect' - this.annotools.drawMarkups(); - jQuery("canvas").css("cursor", "crosshair"); - jQuery("#mergeStep2Button").removeClass("active"); // merge step 2 button - //console.log("added class"); - } - // alert("Creation of markups is disabled on QuIP") - }.bind(this)) - - this.partialDownloadButton.on('click', function(){ - this.annotools.downloadROI(); - }.bind(this)); - - - this.mergebutton1.on('click', function () { - this.mode = 'normal'; - this.annotools.mergeStep1(); - }.bind(this)) - - - this.mergebutton2.on('click', function () { - //console.log(this.mode); - //if(this.mode == 'merge_step2'){ - // this.mode = 'normal'; - //this.setNormalMode(); - // } else { - this.mode = 'merge_step2' - this.annotools.mode = 'rect' - this.annotools.drawMarkups(); - jQuery("canvas").css("cursor", "crosshair"); - jQuery("#mergeStep2Button").addClass("active"); - //} - }.bind(this)) - - - this.mergebutton3.on('click', function () { - this.annotools.generateCompositeDataset(); - }.bind(this)) - - - // Dot Tool start - this.dotToolButton.on('click', function(){ - if (this.annotools.mode == 'dot') { - this.setNormalMode(); - }else{ - this.mode = 'dot'; - this.annotools.mode = 'dot'; - this.annotools.drawDots(); - jQuery("svg").css("cursor", "crosshair"); - jQuery("#drawRectangleButton").removeClass("active"); - jQuery("#drawFreelineButton").removeClass("active"); - jQuery("#mergeStep2Button").removeClass("active"); // merge step 2 button - jQuery("#drawDotButton").addClass("active"); - } - }.bind(this)); - // Dot Tool end - - - this.pencilbutton.on('click', function () { - // if(this.annotools.mode == 'pencil'){ - //this.setNormalMode(); - // } else { - //set pencil mode - this.mode = 'pencil' - this.annotools.mode = 'pencil' - this.annotools.drawMarkups() - jQuery("canvas").css("cursor", "crosshair"); - //jQuery("drawFreelineButton").css("opacity", 1); - //jQuery("#drawRectangleButton").removeClass("active"); - //jQuery("#drawDotButton").removeClass("active"); // Dot Tool - //jQuery("#mergeStep2Button").removeClass("active"); // merge step 2 button - jQuery("#drawFreelineButton").addClass("active"); - //} - - }.bind(this)) - - this.measurebutton.on('click', function () { - this.mode = 'measure' - this.drawMarkups() - }.bind(this)) - - this.hidebutton.on('click', function () { - this.annotools.toggleMarkups() - }.bind(this)) - - this.filterbutton.on('click', function () { - this.toggleAlgorithmSelector() - // this.removeMouseEvents() - // this.promptForAnnotation(null, "filter", this, null) - }.bind(this)) - - - - var toolButtons = jQuery('.toolButton') - toolButtons.each(function () { - jQuery(this).on({ - 'mouseenter': function () { - this.addClass('selected') - }, - 'mouseleave': function () { - this.removeClass('selected') - } - }) - }) - - - } - this.colorMapButton = jQuery('', { - 'class': 'colorMapButton', - 'title': 'ColorMap', - 'src': 'images/colors.svg' - }) - tool.append(this.colorMapButton) - - this.ajaxBusy = jQuery('', { - 'class': 'colorMapButton', - 'id': 'ajaxBusy', - 'style': 'scale(0.5, 1)', - 'src': 'images/progress_bar.gif' - }) - tool.append(this.ajaxBusy) - this.ajaxBusy.hide() - - this.titleButton = jQuery('

', { - 'class': 'titleButton', - 'text': 'caMic Segment Curation App' - }) - tool.append(this.titleButton) - - this.iidbutton = jQuery('

', { - 'class': 'iidButton', - 'text': 'Case ID: ' + this.iid - }) - tool.append(this.iidbutton) - - - if (this.annotationActive) { - } -} + ToolBar.prototype.createButtons = function () { + + // this.tool = jQ(this.source) + var tool = jQuery('#' + 'tool'); // Temporary dom element while we clean up mootools + var self = this; + + // Fetch algorithms for Image + jQuery(document).ready(function () { + // console.log(options) + console.log("self.iid is: " + self.iid); + + jQuery.get('api/Data/getAlgorithmsForImage.php?iid=' + self.iid, function (data) { + d = JSON.parse(data); + // console.log("data before goodalgo is:"+data); + // console.log("d before goodalgo is:"+d); + goodalgo(d, null) + }); + + jQuery('#submitbtn').click(function () { + var selKeys = jQuery('#tree').fancytree('getTree').getSelectedNodes(); + var param = ''; + for (i = 0; i < selKeys.length; i++) { + param = param + '&Val' + (i + 1).toString() + '=' + selKeys[i].title + } + }); + }); + + tool.css({ + 'position': 'absolute', + 'left': this.left, + 'top': this.top, + 'width': this.width, + 'height': this.height, + 'z-index': this.zindex + }); + + tool.addClass('annotools'); // Update Styles + // this.tool.makeDraggable(); //Make it Draggable. + + /** + * Set up Toolbar buttons + */ + if (this.annotationActive) { + + /* Go home, go camicro */ + this.homebutton = jQuery('', { + title: 'QuIP Home', + class: 'toolButton firstToolButtonSpace inactive', + src: 'images/ic_home_white_24px.svg' + }); + tool.append(this.homebutton); + + this.micbutton = jQuery('', { + title: 'caMicroscope', + class: 'toolButton inactive', + src: 'images/camic_vector.svg' + }); + tool.append(this.micbutton); + + /* space */ + this.spacer1 = jQuery('', { + 'class': 'spacerButton inactive', + 'src': 'images/spacer_empty.svg' + }); + tool.append(this.spacer1); + + /* App tools */ + this.filterbutton = jQuery('', { + 'title': 'Filter Markups', + 'class': 'toolButton inactive', + 'src': 'images/filter.svg' + }); + tool.append(this.filterbutton); // Filter Button + + this.rectbutton = jQuery('', { + title: 'Draw Rectangle', + class: 'toolButton inactive', + src: 'images/rect.svg', + id: 'drawRectangleButton' + }); + //tool.append(this.rectbutton) + + this.pencilbutton = jQuery('', { + 'title': 'Draw Freeline', + 'class': 'toolButton inactive', + 'src': 'images/pencil.svg', + 'id': 'drawFreelineButton' + }); + tool.append(this.pencilbutton); // Pencil Tool + + + this.mergebutton1 = jQuery('', { + 'title': 'Save ViewPort', + 'class': 'toolButton inactive', + 'src': 'images/merge1.png' + }); + tool.append(this.mergebutton1); // Merge step 1 + + this.mergebutton2 = jQuery('', { + 'title': 'Save Rectangle And Delete Annotation(s) Within This Area', + 'class': 'toolButton inactive', + 'src': 'images/rect.svg', + 'id': 'mergeStep2Button' + }); + tool.append(this.mergebutton2); // Merge step 2 + + this.measurebutton = jQuery('', { + 'title': 'Measurement Tool', + 'class': 'toolButton inactive', + 'src': 'images/measure.svg' + }); + // tool.append(this.measurebutton) + + this.spacer3 = jQuery('', { + 'class': 'spacerButton inactive', + 'src': 'images/spacer.svg' + }); + tool.append(this.spacer3); + + this.mergebutton3 = jQuery('', { + 'title': 'Generate Composite Dataset', + 'class': 'toolButton inactive', + 'src': 'images/merge2.png', + 'id': 'mergeStep3Button' + }); + tool.append(this.mergebutton3); // Merge step 3 + + this.hidebutton = jQuery('', { + 'title': 'Show/Hide Markups', + 'class': 'toolButton inactive', + 'src': 'images/hide.svg' + }); + // tool.append(this.hidebutton) + + + this.spacer4 = jQuery('', { + 'class': 'spacerButton inactive', + 'src': 'images/spacer.svg' + }); + tool.append(this.spacer4); + + var image_source = 'images/unlock_icon.png'; + if (this.imageStatus == 'lock' || this.imageStatus == 'Lock') + image_source = 'images/lock_icon.png'; + this.lockUnlockButton = jQuery('', { + 'title': 'Lock or Unlock This Image by Super User', + 'class': 'toolButton inactive', + 'src': image_source + }); + tool.append(this.lockUnlockButton); + + /* add a space before enabling */ + this.partialDownloadButton = jQuery('', { + 'title': 'Download Partial Markups (Coming Soon)', + 'class': 'toolButton inactive', + 'src': 'images/partDownload.svg' + }); + //tool.append(this.partialDownloadButton) //Partial Download + + this.spacer5 = jQuery('', { + 'class': 'spacerButton inactive', + 'src': 'images/spacer.svg' + }); + // tool.append(this.spacer5); + + this.dotToolButton = jQuery('', { + 'title': 'Dot Tool', + 'class': 'toolButton inactive', + 'src': 'images/analyze.png', + 'id': 'drawDotButton' + }); + // tool.append(this.dotToolButton); // Dot Tool + + /* + * Event handlers for toolbar buttons + */ + this.homebutton.on('click', function () { + this.mode = 'home'; + var tissueId = annotool.iid; + var cancerType = annotool.cancerType; + window.location.href = "/select.php"; + }.bind(this)); + + + this.micbutton.on('click', function () { + var tissueId = this.iid; + var x1 = annotool.imagingHelper._viewportOrigin['x']; + var y1 = annotool.imagingHelper._viewportOrigin['y']; + var x2 = x1 + annotool.imagingHelper._viewportWidth; + var y2 = y1 + annotool.imagingHelper._viewportHeight; + var zoom = viewer.viewport.getZoom(); + if (zoom < 1.0) zoom = 1.0; + var width, height; + //get image width and height + var url = 'api/Data/getImageInfoByCaseID.php?case_id=' + tissueId; + jQuery.get(url, function (data) { + try { + this_image = JSON.parse(data); + width = this_image[0].width; + height = this_image[0].height; + var x = parseInt(((x1 + x2) / 2.0) * width); + var y = parseInt(((y1 + y2) / 2.0) * height); + window.location.href = "/camicroscope/osdCamicroscope.php?tissueId=" + tissueId + "&x=" + x + "&y=" + y + "&zoom=" + zoom; + } catch (error) { + window.location.href = "/camicroscope/osdCamicroscope.php?tissueId=" + tissueId; + } + }) + }.bind(this)); + + + this.rectbutton.on('click', function () { + //console.log(this.mode); + if (this.annotools.mode == 'rect') { + this.setNormalMode(); + //this. + } else { + this.mode = 'rect'; + this.annotools.mode = 'rect'; + this.annotools.drawMarkups(); + jQuery("canvas").css("cursor", "crosshair"); + jQuery("#mergeStep2Button").removeClass("active"); // merge step 2 button + //console.log("added class"); + } + // alert("Creation of markups is disabled on QuIP") + }.bind(this)); + + this.partialDownloadButton.on('click', function () { + this.annotools.downloadROI(); + }.bind(this)); + + this.pencilbutton.on('click', function () { + if (typeof this.imageStatus == "undefined" || this.imageStatus == "unlock" || this.imageStatus == "Unlock" || this.imageStatus == "") { + this.mode = 'pencil'; + this.annotools.mode = 'pencil'; + this.annotools.drawMarkups(); + if (this.annotools.filter_algorithm) { + jQuery("canvas").css("cursor", "crosshair"); + jQuery("#drawFreelineButton").addClass("active"); + } + else { + this.setNormalMode(); + this.annotools.filter_algorithm = true; + } + } else + alert("This image has been locked. Only super user can unlock this image!"); + }.bind(this)); + + this.mergebutton1.on('click', function () { + if (typeof this.imageStatus == "undefined" || this.imageStatus == "unlock" || this.imageStatus == "Unlock" || this.imageStatus == "") { + this.mode = 'normal'; + this.annotools.mergeStep1(); + } else + alert("This image has been locked. Only super user can unlock this image!"); + }.bind(this)); + + + this.mergebutton2.on('click', function () { + if (typeof this.imageStatus == "undefined" || this.imageStatus == "unlock" || this.imageStatus == "Unlock" || this.imageStatus == "") { + this.mode = 'merge_step2'; + this.annotools.mode = 'rect'; + this.annotools.drawMarkups(); + if (this.annotools.filter_algorithm) { + jQuery("canvas").css("cursor", "crosshair"); + jQuery("#mergeStep2Button").addClass("active"); + } else { + this.setNormalMode(); + this.annotools.filter_algorithm = true; + } + } else + alert("This image has been locked. Only super user can unlock this image!"); + }.bind(this)); + + + this.mergebutton3.on('click', function () { + this.annotools.generateCompositeDataset(); + }.bind(this)); + + this.lockUnlockButton.on('click', function () { + if (this.userType == "superUser") { + var src = this.lockUnlockButton.attr('src'); + var newsrc = (src == 'images/lock_icon.png') ? 'images/unlock_icon.png' : 'images/lock_icon.png'; + this.lockUnlockButton.attr('src', newsrc); + var status = ""; + if (newsrc == 'images/unlock_icon.png') { + this.statusbutton.text('Status: Unlock'); + status = "Unlock"; + } + if (newsrc == 'images/lock_icon.png') { + this.statusbutton.text('Status: Lock'); + status = "Lock"; + } + this.annotools.imageStatusUpdate(status); + window.location.href = "/camicroscope/osdCamicroscope_sc.php?tissueId=" + this.iid; + } else if (this.userType == "user") { + if (this.user_email == this.assignTo) { //this user is assigned to this image + var src = this.lockUnlockButton.attr('src'); + if (src == 'images/unlock_icon.png') {//image status is unlock + this.lockUnlockButton.attr('src', 'images/lock_icon.png'); + this.statusbutton.text('Status: Lock'); + this.annotools.imageStatusUpdate("Lock"); + window.location.href = "/camicroscope/osdCamicroscope_sc.php?tissueId=" + this.iid; + } else + alert("Only super user can activate this button!"); + } else + alert("Only super user/assigned user can activate this button!"); + } else + alert("Only super user can activate this button!"); + }.bind(this)); + + // Dot Tool start + this.dotToolButton.on('click', function () { + if (this.annotools.mode == 'dot') { + this.setNormalMode(); + } else { + this.mode = 'dot'; + this.annotools.mode = 'dot'; + this.annotools.drawDots(); + jQuery("svg").css("cursor", "crosshair"); + jQuery("#drawRectangleButton").removeClass("active"); + jQuery("#drawFreelineButton").removeClass("active"); + jQuery("#mergeStep2Button").removeClass("active"); // merge step 2 button + jQuery("#drawDotButton").addClass("active"); + } + }.bind(this)); + // Dot Tool end + + /* + // DUPE PENCIL BUTTON + this.pencilbutton.on('click', function () { + // if(this.annotools.mode == 'pencil'){ + //this.setNormalMode(); + // } else { + //set pencil mode + this.mode = 'pencil'; + this.annotools.mode = 'pencil'; + this.annotools.drawMarkups(); + jQuery("canvas").css("cursor", "crosshair"); + //jQuery("drawFreelineButton").css("opacity", 1); + //jQuery("#drawRectangleButton").removeClass("active"); + //jQuery("#drawDotButton").removeClass("active"); // Dot Tool + //jQuery("#mergeStep2Button").removeClass("active"); // merge step 2 button + jQuery("#drawFreelineButton").addClass("active"); + //} + + }.bind(this)); + */ + + this.measurebutton.on('click', function () { + this.mode = 'measure'; + this.drawMarkups() + }.bind(this)); + + this.hidebutton.on('click', function () { + this.annotools.toggleMarkups() + }.bind(this)); + + this.filterbutton.on('click', function () { + this.toggleAlgorithmSelector() + // this.removeMouseEvents() + // this.promptForAnnotation(null, "filter", this, null) + }.bind(this)); + + this.partialDownloadButton.on('click', function () { + this.annotools.downloadROI(); + }.bind(this)); + + + var toolButtons = jQuery('.toolButton'); + toolButtons.each(function () { + jQuery(this).on({ + 'mouseenter': function () { + // highlight button + this.addClass('selected') + }, + 'mouseleave': function () { + // un-highlight button + this.removeClass('selected') + } + }) + }) + } + this.colorMapButton = jQuery('', { + 'class': 'colorMapButton', + 'title': 'ColorMap', + 'src': 'images/colors.svg' + }); + tool.append(this.colorMapButton); + + this.ajaxBusy = jQuery('', { + 'class': 'colorMapButton', + 'id': 'ajaxBusy', + 'style': 'scale(0.5, 1)', + 'src': 'images/progress_bar.gif' + }); + tool.append(this.ajaxBusy); + this.ajaxBusy.hide(); + + this.titleButton = jQuery('

', { + 'class': 'titleButton', + 'id': 'titleButton', + 'text': 'caMic Segment Curation App' + }); + tool.append(this.titleButton); + + this.iidbutton = jQuery('

', { + 'class': 'iidButton', + 'text': 'Display ID: ' + this.displayId + }); + tool.append(this.iidbutton); + + if(typeof this.imageStatus == "undefined"){ + var image_status=""; + } else { + var image_status=this.imageStatus; + } + this.statusbutton = jQuery('

', { + 'class': 'statusButton', + //if(this.imageStatus =='Lock') + // 'text': 'Status: ' + 'Lock' + //else if(this.imageStatus =='Unlock') + 'text': 'Status: ' + image_status + //else + //'text': 'Status: ' + ' ' + }); + tool.append(this.statusbutton); + + if (this.annotationActive) { + // empty block + } + }; +}); diff --git a/js/annotationtools_sc/annotools-openseajax-handler.js b/js/annotationtools_sc/annotools-openseajax-handler.js index 29a33ccf9..767923565 100644 --- a/js/annotationtools_sc/annotools-openseajax-handler.js +++ b/js/annotationtools_sc/annotools-openseajax-handler.js @@ -1,295 +1,322 @@ /* -Copyright (C) 2013 Sanjay Agravat , Ashish Sharma + Copyright (C) 2013 Sanjay Agravat , Ashish Sharma -This file is a zoom and pan handler for OpenSeadragon and annotools.js to support resizing annotations on certain mouse events. - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -*/ + This file is a zoom and pan handler for OpenSeadragon and annotools.js to support resizing annotations on certain mouse events. + + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ var AnnotoolsOpenSeadragonHandler = new Class({ - initialize: function (viewer, options) { - this.viewer = viewer - this.state = 'none' - this.stateTarget = null - this.stateOrigin = null - this.scale = options.ratio || 1.3 - this.lastCenter = {x: 0, y: 0} - this.objectCenterPts = {} - this.originalCoords = [] - this.originalDivCoords = [] - this.zoom = viewer.viewport.getZoom() - this.zoomBase = viewer.viewport.getZoom() - this.zooming = false - this.panning = false - this.animateWaitTime = options.animateWaitTime || 300 - - this._setupOpenSeadragonButtonHandlers() - - // global object reference used when the "this" object is referring to the window - window.annotationHandler = this - }, - - /* - Redefines the button handlers from the OpenSeadragon button bar - for the onRelease event. Handles Zoom in, Zoom out, and Home - buttons. - */ - _setupOpenSeadragonButtonHandlers: function () { - for (var i = 0; i < this.viewer.buttons.buttons.length; i++) { - var button = this.viewer.buttons.buttons[i] - if (button.tooltip.toLowerCase() == 'zoom in') { - var onZoomInRelease = button.onRelease - var zoomIn = this.handleZoomIn - button.onRelease = function (args) { - $$('svg')[0].setStyle('opacity', 1) - onZoomInRelease(args) - setTimeout(function () { - // zoomIn() - $$('svg')[0].setStyle('opacity', 1) - }, annotationHandler.animateWaitTime) - } - } - else if (button.tooltip.toLowerCase() == 'zoom out') { - var onZoomOutRelease = button.onRelease - var zoomOut = this.handleZoomOut - button.onRelease = function (args) { - $$('svg')[0].setStyle('opacity', 0) - onZoomOutRelease(args) - setTimeout(function () { - // zoomOut() - $$('svg')[0].setStyle('opacity', 1) - }, annotationHandler.animateWaitTime) + initialize: function (viewer, options) { + this.viewer = viewer; + this.state = 'none'; + this.stateTarget = null; + this.stateOrigin = null; + this.scale = options.ratio || 1.3; + this.lastCenter = {x: 0, y: 0}; + this.objectCenterPts = {}; + this.originalCoords = []; + this.originalDivCoords = []; + this.zoom = viewer.viewport.getZoom(); + this.zoomBase = viewer.viewport.getZoom(); + this.zooming = false; + this.panning = false; + this.animateWaitTime = options.animateWaitTime || 300; + + this._setupOpenSeadragonButtonHandlers(); + + // global object reference used when the "this" object is referring to the window + window.annotationHandler = this + }, + + /* + Redefines the button handlers from the OpenSeadragon button bar + for the onRelease event. Handles Zoom in, Zoom out, and Home + buttons. + */ + _setupOpenSeadragonButtonHandlers: function () { + for (var i = 0; i < this.viewer.buttons.buttons.length; i++) { + var button = this.viewer.buttons.buttons[i]; + if (button.tooltip.toLowerCase() == 'zoom in') { + var onZoomInRelease = button.onRelease; + var zoomIn = this.handleZoomIn; + button.onRelease = function (args) { + $$('svg')[0].setStyle('opacity', 1); + onZoomInRelease(args); + setTimeout(function () { + // zoomIn() + $$('svg')[0].setStyle('opacity', 1) + }, annotationHandler.animateWaitTime) + } + } + else if (button.tooltip.toLowerCase() == 'zoom out') { + var onZoomOutRelease = button.onRelease; + var zoomOut = this.handleZoomOut; + button.onRelease = function (args) { + $$('svg')[0].setStyle('opacity', 0); + onZoomOutRelease(args); + setTimeout(function () { + // zoomOut() + $$('svg')[0].setStyle('opacity', 1) + }, annotationHandler.animateWaitTime) + } + } } - } - } - }.protect(), - - goHome: function (annot) { - annot.getAnnot() - }, - - handleZoomIn: function (annot) { - zooming = true - console.log('handleZoomIn') - var center = viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)) - if (annotationHandler.lastCenter.x != center.x || annotationHandler.lastCenter.y != center.y) { - scale = 1.3 - annotationHandler.zoom++ - var centerPt = - viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)) - $('originpt').setProperty('cx', centerPt.x) - $('originpt').setProperty('cy', centerPt.y) - - - for (var i = 0; i < $('viewport').getChildren().length; i++) { - var object = $('viewport').getChildren()[i] - // var centerPt = $('center')[0] - var bbox = object.getBBox() - - var newLocation = viewer.viewport.pixelFromPoint(annotationHandler.objectCenterPts[i]) - - var distance = newLocation.distanceTo(center) - if (object.tagName == 'ellipse') { - object.setAttribute('rx', (bbox.width / 2) * scale) - object.setAttribute('ry', (bbox.height / 2) * scale) - object.setAttribute('cx', newLocation.x) - object.setAttribute('cy', newLocation.y) + }.protect(), + + goHome: function (annot) { + annot.getAnnot() + }, + + handleZoomIn: function (annot) { + zooming = true; + console.log('handleZoomIn'); + var center = viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)); + if (annotationHandler.lastCenter.x != center.x || annotationHandler.lastCenter.y != center.y) { + scale = 1.3; + annotationHandler.zoom++; + var centerPt = + viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)); + $('originpt').setProperty('cx', centerPt.x); + $('originpt').setProperty('cy', centerPt.y); + + + for (var i = 0; i < $('viewport').getChildren().length; i++) { + var object = $('viewport').getChildren()[i]; + // var centerPt = $('center')[0] + var bbox = object.getBBox(); + + var newLocation = viewer.viewport.pixelFromPoint(annotationHandler.objectCenterPts[i]); + + var distance = newLocation.distanceTo(center); + if (object.tagName == 'ellipse') { + object.setAttribute('rx', (bbox.width / 2) * scale); + object.setAttribute('ry', (bbox.height / 2) * scale); + object.setAttribute('cx', newLocation.x); + object.setAttribute('cy', newLocation.y) + } + else if (object.tagName == 'rect') { + object.setAttribute('width', (bbox.width) * scale); + object.setAttribute('height', (bbox.height) * scale); + object.setAttribute('x', newLocation.x - (bbox.width / 2) * scale); + object.setAttribute('y', newLocation.y - (bbox.height / 2) * scale) + } else { + var points = String.split(object.getAttribute('points').trim(), ' '); + var newLocationRelPt = viewer.viewport.pointFromPixel(newLocation); + var distances = annotationHandler.originalCoords[i].distances; + var pointsStr = ''; + for (var j = 0; j < distances.length - 1; j++) { + var pointPair = distances[j].plus(newLocationRelPt); + var pixelPoint = viewer.viewport.pixelFromPoint(pointPair); + pointsStr += pixelPoint.x + ',' + pixelPoint.y + ' ' + } + object.setAttribute('points', pointsStr) + } + + var div = $$('div.annotcontainer')[i]; + div.style.left = newLocation.x - (bbox.width / 2) * scale + 'px'; + div.style.top = newLocation.y - (bbox.height / 2) * scale + 'px'; + div.style.width = (bbox.width) * scale + 'px'; + div.style.height = (bbox.height) * scale + 'px' + } } - else if (object.tagName == 'rect') { - object.setAttribute('width', (bbox.width) * scale) - object.setAttribute('height', (bbox.height) * scale) - object.setAttribute('x', newLocation.x - (bbox.width / 2) * scale) - object.setAttribute('y', newLocation.y - (bbox.height / 2) * scale) - }else { - var points = String.split(object.getAttribute('points').trim(), ' ') - var newLocationRelPt = viewer.viewport.pointFromPixel(newLocation) - var distances = annotationHandler.originalCoords[i].distances - var pointsStr = '' - for (var j = 0; j < distances.length - 1; j++) { - var pointPair = distances[j].plus(newLocationRelPt) - var pixelPoint = viewer.viewport.pixelFromPoint(pointPair) - pointsStr += pixelPoint.x + ',' + pixelPoint.y + ' ' - } - object.setAttribute('points', pointsStr) + + annotationHandler.lastCenter = center; + zooming = false + }, + + handleZoomOut: function () { + zooming = true; + var center = viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)); + console.log('handleZoomOut'); + if (annotationHandler.lastCenter.x != center.x || annotationHandler.lastCenter.y != center.y) { + scale = 1 / 1.3; + annotationHandler.zoom--; + + var centerPt = + viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)); + $('originpt').setProperty('cx', centerPt.x); + $('originpt').setProperty('cy', centerPt.y); + + for (var i = 0; i < $('viewport').getChildren().length; i++) { + var object = $('viewport').getChildren()[i]; + var bbox = object.getBBox(); + + var newLocation = viewer.viewport.pixelFromPoint(annotationHandler.objectCenterPts[i]); + + if (object.tagName == 'ellipse') { + object.setAttribute('rx', (bbox.width / 2) * scale); + object.setAttribute('ry', (bbox.height / 2) * scale); + object.setAttribute('cx', newLocation.x); + object.setAttribute('cy', newLocation.y) + } + else if (object.tagName == 'rect') { + object.setAttribute('width', (bbox.width) * scale); + object.setAttribute('height', (bbox.height) * scale); + object.setAttribute('x', newLocation.x - (bbox.width / 2) * scale); + object.setAttribute('y', newLocation.y - (bbox.height / 2) * scale) + } else { + var points = String.split(object.getAttribute('points').trim(), ' '); + var newLocationRelPt = viewer.viewport.pointFromPixel(newLocation); + var distances = annotationHandler.originalCoords[i].distances; + var pointsStr = ''; + for (var j = 0; j < distances.length - 1; j++) { + var pointPair = distances[j].plus(newLocationRelPt); + var pixelPoint = viewer.viewport.pixelFromPoint(pointPair); + pointsStr += pixelPoint.x + ',' + pixelPoint.y + ' ' + } + object.setAttribute('points', pointsStr) + } + var div = $$('div.annotcontainer')[i]; + div.style.left = newLocation.x - (bbox.width / 2) * scale + 'px'; + div.style.top = newLocation.y - (bbox.height / 2) * scale + 'px'; + div.style.width = (bbox.width) * scale + 'px'; + div.style.height = (bbox.height) * scale + 'px' + } } - var div = $$('div.annotcontainer')[i] - div.style.left = newLocation.x - (bbox.width / 2) * scale + 'px' - div.style.top = newLocation.y - (bbox.height / 2) * scale + 'px' - div.style.width = (bbox.width) * scale + 'px' - div.style.height = (bbox.height) * scale + 'px' - } - } + annotationHandler.lastCenter = center; + zooming = false + }, - annotationHandler.lastCenter = center - zooming = false - }, - - handleZoomOut: function () { - zooming = true - var center = viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)) - console.log('handleZoomOut') - if (annotationHandler.lastCenter.x != center.x || annotationHandler.lastCenter.y != center.y) { - scale = 1 / 1.3 - annotationHandler.zoom-- - - var centerPt = - viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)) - $('originpt').setProperty('cx', centerPt.x) - $('originpt').setProperty('cy', centerPt.y) - - for (var i = 0; i < $('viewport').getChildren().length; i++) { - var object = $('viewport').getChildren()[i] - var bbox = object.getBBox() - - var newLocation = viewer.viewport.pixelFromPoint(annotationHandler.objectCenterPts[i]) - - if (object.tagName == 'ellipse') { - object.setAttribute('rx', (bbox.width / 2) * scale) - object.setAttribute('ry', (bbox.height / 2) * scale) - object.setAttribute('cx', newLocation.x) - object.setAttribute('cy', newLocation.y) + handleMouseMove: function (evt) { + // console.log("..") + if (evt.preventDefault) { + // console.log("frozen") + evt.preventDefault() } - else if (object.tagName == 'rect') { - object.setAttribute('width', (bbox.width) * scale) - object.setAttribute('height', (bbox.height) * scale) - object.setAttribute('x', newLocation.x - (bbox.width / 2) * scale) - object.setAttribute('y', newLocation.y - (bbox.height / 2) * scale) - }else { - var points = String.split(object.getAttribute('points').trim(), ' ') - var newLocationRelPt = viewer.viewport.pointFromPixel(newLocation) - var distances = annotationHandler.originalCoords[i].distances - var pointsStr = '' - for (var j = 0; j < distances.length - 1; j++) { - var pointPair = distances[j].plus(newLocationRelPt) - var pixelPoint = viewer.viewport.pixelFromPoint(pointPair) - pointsStr += pixelPoint.x + ',' + pixelPoint.y + ' ' - } - object.setAttribute('points', pointsStr) + if (this.state == 'pan') { + // $('svg')[0].hide(); + if ($$('svg')[0]) { + $$('svg')[0].setStyle('opacity', 0); + } + + var pixel = OpenSeadragon.getMousePosition(evt).minus(OpenSeadragon.getElementPosition(viewer.element)); + // console.log("pixel", pixel); + var point = viewer.viewport.pointFromPixel(pixel); + // console.log("point", point); + } + }, + + /** + * handleMouseUp + * + * @param evt + */ + handleMouseUp: function (evt) { + // console.log("mouse up") + // if (evt.target.tagName.toLowerCase() == "button" || evt.target.tagName.toLowerCase() == "div") { + if (evt.target.tagName.toLowerCase() == 'button' || evt.target.tagName.toLowerCase() == 'input') { + // console.log("handleMouseUp: " + evt.target.tagName) + return } - var div = $$('div.annotcontainer')[i] - div.style.left = newLocation.x - (bbox.width / 2) * scale + 'px' - div.style.top = newLocation.y - (bbox.height / 2) * scale + 'px' - div.style.width = (bbox.width) * scale + 'px' - div.style.height = (bbox.height) * scale + 'px' - } - } - annotationHandler.lastCenter = center - zooming = false - }, + if (evt.preventDefault) + evt.preventDefault(); + + if (this.state == 'pan') { + this.state = 'up'; + + var pos = OpenSeadragon.getElementPosition(viewer.element); + // console.log("pos", pos); + + var pixel = OpenSeadragon.getMousePosition(evt).minus(pos); + // console.log("pixel", pixel); + + var diff = pixel.minus(this.stateOrigin); + + // handles a mouse click (zoom and pan to) + // otherwise we will handle the pan event + if (diff.x == 0 && diff.y == 0) { + + // setTimeout(function() { + // annotationHandler.handleZoomIn() + if ($$('svg')[0]) { + $$('svg')[0].setStyle('opacity', 1) + } + // }, annotationHandler.animateWaitTime) + + } else { + $$('originpt').setProperty('cx', + viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)).x); + $$('originpt').setProperty('cy', + viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)).y); + + // $('svg')[0].show(); + if ($$('svg')[0]) { + $$('svg')[0].setStyle('opacity', 1); + } + + for (var i = 0; i < $$('viewport').getChildren().length; i++) { + var object = $('viewport').getChildren()[i]; + // object.setAttribute("style", style="fill:none;stroke:lime;stroke-width:2") + var bbox = object.getBBox(); + if (object.tagName == 'ellipse') { + var currX = bbox.x + bbox.width / 2; + var currY = bbox.y + bbox.height / 2; + object.setAttribute('cx', currX + diff.x); + object.setAttribute('cy', currY + diff.y) + } + else if (object.tagName == 'rect') { + object.setAttribute('x', bbox.x + diff.x); + object.setAttribute('y', bbox.y + diff.y) + } else { + var points = String.split(object.getAttribute('points').trim(), ' '); + var pointsStr = ''; + for (var j = 0; j < points.length; j++) { + var pointPair = String.split(points[j], ','); + pointsStr += (parseFloat(pointPair[0]) + diff.x) + + ',' + + (parseFloat(pointPair[1]) + diff.y) + ' ' + } + object.setAttribute('points', pointsStr) + } + + var div = $$('div.annotcontainer')[i]; + + div.style.left = (bbox.x + diff.x) + 'px'; + div.style.top = (bbox.y + diff.y) + 'px' + } + } + } + }, - handleMouseMove: function (evt) { - // console.log("..") - if (evt.preventDefault) { - // console.log("frozen") - evt.preventDefault() - } - if (this.state == 'pan') { - // $('svg')[0].hide(); - $$('svg')[0].setStyle('opacity', 0) - var pixel = OpenSeadragon.getMousePosition(evt).minus - ;(OpenSeadragon.getElementPosition(viewer.element)) - var point = viewer.viewport.pointFromPixel(pixel) - } - }, - - handleMouseUp: function (evt) { - // console.log("mouse up") - // if (evt.target.tagName.toLowerCase() == "button" || evt.target.tagName.toLowerCase() == "div") { - if (evt.target.tagName.toLowerCase() == 'button' || evt.target.tagName.toLowerCase() == 'input') { - // console.log("here"); - // console.log("handleMouseUp: " + evt.target.tagName) - return - } + handleMouseDown: function (evt) { - if (evt.preventDefault) - evt.preventDefault() - - if (this.state == 'pan') { - this.state = 'up' - var pixel = - OpenSeadragon.getMousePosition(evt).minus - ;(OpenSeadragon.getElementPosition(viewer.element)) - - var diff = pixel.minus(this.stateOrigin) - - // handles a mouse click (zoom and pan to) - // otherwise we will handle the pan event - if (diff.x == 0 && diff.y == 0) { - - // setTimeout(function() { - // annotationHandler.handleZoomIn() - $$('svg')[0].setStyle('opacity', 1) - // }, annotationHandler.animateWaitTime) - - }else { - $$('originpt').setProperty('cx', - viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)).x) - $$('originpt').setProperty('cy', - viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)).y) - - // $('svg')[0].show(); - $$('svg')[0].setStyle('opacity', 1) - for (var i = 0; i < $$('viewport').getChildren().length; i++) { - var object = $('viewport').getChildren()[i] - // object.setAttribute("style", style="fill:none;stroke:lime;stroke-width:2") - var bbox = object.getBBox() - if (object.tagName == 'ellipse') { - var currX = bbox.x + bbox.width / 2 - var currY = bbox.y + bbox.height / 2 - object.setAttribute('cx', currX + diff.x) - object.setAttribute('cy', currY + diff.y) - } - else if (object.tagName == 'rect') { - object.setAttribute('x', bbox.x + diff.x) - object.setAttribute('y', bbox.y + diff.y) - }else { - var points = String.split(object.getAttribute('points').trim(), ' ') - var pointsStr = '' - for (var j = 0; j < points.length; j++) { - var pointPair = String.split(points[j], ',') - pointsStr += (parseFloat(pointPair[0]) + diff.x) + - ',' + - (parseFloat(pointPair[1]) + diff.y) + ' ' - } - object.setAttribute('points', pointsStr) - } + // Allow interactions on the annotation creation form elements + if (evt.target.tagName.toLowerCase() == 'button' || evt.target.tagName.toLowerCase() == 'input' || evt.target.tagName.toLowerCase() == 'select') { + return + } + + if (evt.preventDefault) { + evt.preventDefault(); + } - var div = $$('div.annotcontainer')[i] + this.state = 'pan'; + var pos = OpenSeadragon.getElementPosition(viewer.element); + // console.log("pos", pos); + var pixel = OpenSeadragon.getMousePosition(evt).minus(pos); + // console.log("pixel", pixel); - div.style.left = (bbox.x + diff.x) + 'px' - div.style.top = (bbox.y + diff.y) + 'px' + if ($$('svg')[0]) { + //console.log("$$('svg')[0]", $$('svg')[0]); + $$('svg')[0].setStyle('opacity', 0); } - } - } - }, - handleMouseDown: function (evt) { + this.stateOrigin = pixel; + }, + + handleMouseWheel: function (evt) { + if (evt.preventDefault) + evt.preventDefault(); + if ($$('svg')[0]) { + $$('svg')[0].setStyle('opacity', 0) + } - // Allow interactions on the annotation creation form elements - if (evt.target.tagName.toLowerCase() == 'button' || evt.target.tagName.toLowerCase() == 'input' || evt.target.tagName.toLowerCase() == 'select') { - return } - if (evt.preventDefault) - evt.preventDefault() - this.state = 'pan' - var pixel = OpenSeadragon.getMousePosition(evt).minus - ;(OpenSeadragon.getElementPosition(viewer.element)) - - $$('svg')[0].setStyle('opacity', 0) - this.stateOrigin = pixel - }, - - handleMouseWheel: function (evt) { - if (evt.preventDefault) - evt.preventDefault() - - $$('svg')[0].setStyle('opacity', 0) - } -}) +}); diff --git a/js/annotationtools_sc/geoJSONHandler_sc.js b/js/annotationtools_sc/geoJSONHandler_sc.js index 4341b7a5f..e876dba2f 100644 --- a/js/annotationtools_sc/geoJSONHandler_sc.js +++ b/js/annotationtools_sc/geoJSONHandler_sc.js @@ -156,7 +156,6 @@ annotools.prototype.generateCanvas = function (annotations) { // console.log(container) var width = parseInt(container.offsetWidth) var height = parseInt(container.offsetHeight) - /* Why is there an ellipse in the center? */ /* var svgHtml = '' svgHtml += '' @@ -217,7 +216,6 @@ annotools.prototype.generateSVG = function (annotations) { // console.log(container) var width = parseInt(container.offsetWidth) var height = parseInt(container.offsetHeight) - /* Why is there an ellipse in the center? */ var svgHtml = '' svgHtml += '' svgHtml += '' @@ -282,24 +280,35 @@ annotools.prototype.generateSVG = function (annotations) { html: svgHtml }).inject(container) } - - var ctrl = false; - var alt = false; - jQuery(document).keydown(function(event){ - //console.log("control"); - //console.log(event); - if(event.which == 17 || event.which == 91)//Ctrl key and left window key - ctrl = true; - else if (event.which == 18 || event.which == 92)//Alt key and right window key - alt = true; - }); - - jQuery(document).keyup(function(){ + + var ctrl = false; + var alt = false; + // Use CTRL & Windows key (command key on Mac) + jQuery(document).keydown(function (event) { + + if (event.which === 17 || event.which === 91) + { + //Ctrl key and left window key + console.log(event.which); + ctrl = true; + } + else if (event.which === 18 || event.which === 92) + { + //Alt key and right window key + console.log(event.which); + alt = true; + } + //console.log("ctrl: " + ctrl + ", alt: " + alt); + + }); + + jQuery(document).keyup(function () { ctrl = false; - alt = false; - }); + alt = false; + }); - jQuery('.annotationsvg').mousedown(function (event) { + //jQuery(".annotationsvg").mousedown(function (event) { + jQuery(".annotationsvg").click(function (event) { //console.log(event.which); if(ctrl){ //console.log("double clicked"); @@ -324,7 +333,7 @@ annotools.prototype.generateSVG = function (annotations) { jQuery("#"+event.target.id).css("opacity", 1); var id = event.target.id var url = "api/Data/getROI.php?id="+id; - console.log("id:"+url); + console.log("url:"+url); console.log("id:"+id); var content = "

Annotation Details

" + "
"; diff --git a/js/annotationtools_sc/osdAnnotationTools_sc.js b/js/annotationtools_sc/osdAnnotationTools_sc.js index 9e7366571..c9d52d292 100644 --- a/js/annotationtools_sc/osdAnnotationTools_sc.js +++ b/js/annotationtools_sc/osdAnnotationTools_sc.js @@ -1,32 +1,36 @@ /* Copyright (C) 2012 Shaohuan Li , Ashish Sharma This file is part of Biomedical Image Viewer developed under the Google of Summer of Code 2012 program. - + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 - + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ +console.log("osdAnnotationTools_sc.js"); + var annotools = function (options) { - this.AnnotationStore = new AnnotationStore(options.iid) + this.AnnotationStore = new AnnotationStore(options.iid); - this.annotationActive = isAnnotationActive() + this.annotationActive = isAnnotationActive(); this.ratio = options.ratio || 0.005; // One pixel equals to the length in real situation. Will be used in the measurement tool this.maxWidth = options.maxWidth || 4000 // MaxWidth of the Image this.maxHeight = options.maxHeight || 800 // //MaxHeight of the Image this.initialized = false this.color = options.color || 'lime' // Default Annotation Color - this.iidDecoded = decodeURI(options.iid) this.canvas = options.canvas; // The canvas Element that The Use will be drawing annotatoins on. this.iid = options.iid || null // The Image ID - this.cancerType=options.cancerType; + this.cancerType=options.cancerType + this.imageStatus=options.imageStatus + this.assignTo = options.assignTo + this.userType = options.userType + this.user_email = options.user_email this.annotVisible = true // The Annotations are Set to be visible at the First Loading this.mode = 'default' // The Mode is Set to Default - this.viewer = options.viewer this.imagingHelper = this.viewer.imagingHelper this.mpp = options.mpp @@ -36,1194 +40,1223 @@ var annotools = function (options) { this.x2 = 1.0 this.y1 = 0.0 this.y2 = 1.0 + this.filter_algorithm = true - this.annotationHandler = options.annotationHandler || new AnnotoolsOpenSeadragonHandler() - /* - * OpenSeaDragon events - */ - this.viewer.addHandler('animation-finish', function (event) { - var self = this - self.getMultiAnnot() - }.bind(this)) - - this.viewer.addHandler('animation-start', function (event) { - var markup_svg = document.getElementById('markups') - if (markup_svg) { - // console.log("destroying") - markup_svg.destroy() - // console.log("destroyed") - } - }) + this.annotationHandler = options.annotationHandler || new AnnotoolsOpenSeadragonHandler(); + /* + * OpenSeaDragon events + */ + this.viewer.addHandler('animation-finish', function (event) { + var self = this; + self.getMultiAnnot() + }.bind(this)); + + this.viewer.addHandler('animation-start', function (event) { + var markup_svg = document.getElementById('markups'); + if (markup_svg) { + // console.log("destroying") + markup_svg.destroy() + // console.log("destroyed") + } + }); - window.addEvent('domready', function () { - /*temp*/ - var self = this - self.setupHandlers() + window.addEvent('domready', function () { + /*temp*/ + var self = this; + self.setupHandlers() - // this.getAnnot() - // ToolBar.createButtons() - }.bind(this)) // Get the annotation information and Create Buttons + // this.getAnnot() + // ToolBar.createButtons() + }.bind(this)); // Get the annotation information and Create Buttons - if (this.annotationActive) { - // this.getAnnot() - } - - this.imagingHelper.addHandler('image-view-changed', function (event) { - // this.getAnnot() - }.bind(this)) - - this.messageBox = new Element('div', { - 'id': 'messageBox' - }).inject(document.body) // Create A Message Box - - this.showMessage('Press white space to toggle annotations') - /* - this.drawLayer = jQuery('
', { - html: "", - styles: { - position: 'absolute', - 'z-index': 1 - } - }) - jQuery("body").append(this.drawLayer) - */ - - this.drawLayer = new Element('div', { - html: '', - styles: { - position: 'absolute', - 'z-index': 1 + if (this.annotationActive) { + // this.getAnnot() } - }).inject(document.body) // drawLayer will hide by default - - // this.drawCanvas = jQuery('') - // this.drawCanvas.css({"position": "absolute", "z-index": 1}) - // this.drawLayer.append(this.drawCanvas) - - this.drawCanvas = new Element('canvas').inject(this.drawLayer) - // this.drawLayer.hide() - /* - this.magnifyGlass = new Element('div', { - 'class': 'magnify' - }).inject(document.body) //Magnify glass will hide by default - this.magnifyGlass.hide() - */ - this.magnifyGlass = jQuery('
', { - 'class': 'magnify' - }) - jQuery('body').append(this.magnifyGlass) - this.magnifyGlass.hide() -} + + this.imagingHelper.addHandler('image-view-changed', function (event) { + // this.getAnnot() + }.bind(this)); + + this.messageBox = new Element('div', { + 'id': 'messageBox' + }).inject(document.body); // Create A Message Box + + this.showMessage('Press white space to toggle annotations'); + /* + this.drawLayer = jQuery('
', { + html: "", + styles: { + position: 'absolute', + 'z-index': 1 + } + }) + jQuery("body").append(this.drawLayer) + */ + + this.drawLayer = new Element('div', { + html: '', + styles: { + position: 'absolute', + 'z-index': 1 + } + }).inject(document.body); // drawLayer will hide by default + + // this.drawCanvas = jQuery('') + // this.drawCanvas.css({"position": "absolute", "z-index": 1}) + // this.drawLayer.append(this.drawCanvas) + + this.drawCanvas = new Element('canvas').inject(this.drawLayer); + // this.drawLayer.hide() + /* + this.magnifyGlass = new Element('div', { + 'class': 'magnify' + }).inject(document.body) //Magnify glass will hide by default + this.magnifyGlass.hide() + */ + this.magnifyGlass = jQuery('
', { + 'class': 'magnify' + }); + jQuery('body').append(this.magnifyGlass); + this.magnifyGlass.hide() +}; annotools.prototype.destroyMarkups = function (viewer) { - var markup_svg = document.getElementById('markups') - if (markup_svg) { - // console.log("destroying") - markup_svg.destroy() - // console.log("destroyed") - } -} + var markup_svg = document.getElementById('markups'); + if (markup_svg) { + // console.log("destroying") + markup_svg.destroy() + // console.log("destroyed") + } +}; annotools.prototype.getMultiAnnot = function (viewer) { - console.log("getMultiAnnot"); - var opa = [] + var self = this; + this.x1 = this.imagingHelper._viewportOrigin['x']; + this.y1 = this.imagingHelper._viewportOrigin['y']; + this.x2 = this.x1 + this.imagingHelper._viewportWidth; + this.y2 = this.y1 + this.imagingHelper._viewportHeight; + + boundX1 = this.imagingHelper.physicalToLogicalX(200); + boundY1 = this.imagingHelper.physicalToLogicalY(20); + boundX2 = this.imagingHelper.physicalToLogicalX(20); + boundY2 = this.imagingHelper.physicalToLogicalY(20); + var boundX = boundX1 - this.x1; + var boundY = boundX; - var val1 = '' - var val2 = '' - var val3 = '' + var max = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(9), this.imagingHelper.physicalToDataY(9)); + var origin = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(0), this.imagingHelper.physicalToDataY(0)); + var area = (max.x - origin.x) * (max.y - origin.y); + //algorithms.push('test') - var algorithms = [] + var t1 = 0; - /* - if (jQuery('#tree').attr('algotree')) { - var selalgos = jQuery('#tree').fancytree('getTree').getSelectedNodes() - console.log("selalgos is: "+selalgos); - for (i = 0; i < selalgos.length; i++) { - //console.log(selalgos[i]) - algorithms.push(selalgos[i].refKey) - console.log("selalgos refKey is: "+selalgos[i].refKey); - // opa["Val" + (i + 1).toString()] = selalgos[i].refKey + if (SELECTED_ALGORITHM_LIST.length) { + SELECTED_ALGORITHM_LIST = SELECTED_ALGORITHM_LIST.sort(); + var algorithms = SELECTED_ALGORITHM_LIST; + var myList = OVERLAY_LIST; + + self.fetchAnnots(area, algorithms, myList); + } else { + self.setupHandlers(); + self.destroyMarkups(); + // destroy canvas } - }*/ - - console.log("algorithm_list", ALGORITHM_LIST); - console.log("selected_algorithm_list", SELECTED_ALGORITHM_LIST); - SELECTED_ALGORITHM_LIST = SELECTED_ALGORITHM_LIST.sort(); - console.log("...."); - algorithms = SELECTED_ALGORITHM_LIST; - - //console.log(algorithms); - var self = this - this.x1 = this.imagingHelper._viewportOrigin['x'] - this.y1 = this.imagingHelper._viewportOrigin['y'] - this.x2 = this.x1 + this.imagingHelper._viewportWidth - this.y2 = this.y1 + this.imagingHelper._viewportHeight - - boundX1 = this.imagingHelper.physicalToLogicalX(200) - boundY1 = this.imagingHelper.physicalToLogicalY(20) - boundX2 = this.imagingHelper.physicalToLogicalX(20) - boundY2 = this.imagingHelper.physicalToLogicalY(20) - var boundX = boundX1 - this.x1 - var boundY = boundX - - var max = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(9), this.imagingHelper.physicalToDataY(9)) - var origin = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(0), this.imagingHelper.physicalToDataY(0)) - var area = (max.x - origin.x) * (max.y - origin.y) - //algorithms.push('test') - - var t1 = 0 - if (algorithms.length) { - this.toolBar.titleButton.hide() - this.toolBar.ajaxBusy.show() - this.annotations = this.AnnotationStore.fetchAnnotations(this.x1, this.y1, this.x2, this.y2, area, algorithms, function (data) { - //console.log(" fetchAnnotations data is: "+data) - self.annotations = data - self.displayGeoAnnots() - self.setupHandlers() - var t2 = 10 - - self.toolBar.titleButton.show() - self.toolBar.ajaxBusy.hide() - }) - } else { - self.setupHandlers() - self.destroyMarkups() - // destroy canvas - } -} +}; + +annotools.prototype.filterit = function (a, b) { + + var aa = []; + var bb = []; + for (var i = 0; i < b.length; i++) { + bb.push(b[i].execid); + + } + + // If we've already displayed the tiles + // remove it from the "todo" list. + for (var i = 0; i < a.length; i++) { + var idx = bb.indexOf(a[i]); + if (idx < 0) { + aa.push(a[i]); + + } + } + + return aa; +}; + +annotools.prototype.fetchAnnots = function (area, SELECTED_ALGORITHM_LIST, OVERLAY_LIST) { + var self = this; + var algorithms = self.filterit(SELECTED_ALGORITHM_LIST, OVERLAY_LIST); + //console.log("**** algorithms ****", algorithms); + + if (algorithms.length) { + + this.toolBar.titleButton.hide(); + this.toolBar.ajaxBusy.show(); + + this.annotations = this.AnnotationStore.fetchAnnotations(self.x1, self.y1, self.x2, self.y2, area, algorithms, function (data) { + self.annotations = data; + self.displayGeoAnnots(); + self.setupHandlers(); + + self.toolBar.titleButton.show(); + self.toolBar.ajaxBusy.hide(); + }); + + } else { + self.setupHandlers(); + self.destroyMarkups(); + // destroy canvas + } +}; annotools.prototype.getAnnot = function (viewer) // Get Annotation from the API { - var self = this - this.x1 = this.imagingHelper._viewportOrigin['x'] - this.y1 = this.imagingHelper._viewportOrigin['y'] - this.x2 = this.x1 + this.imagingHelper._viewportWidth - this.y2 = this.y1 + this.imagingHelper._viewportHeight - - boundX1 = this.imagingHelper.physicalToLogicalX(200) - boundY1 = this.imagingHelper.physicalToLogicalY(20) - boundX2 = this.imagingHelper.physicalToLogicalX(20) - boundY2 = this.imagingHelper.physicalToLogicalY(20) - var boundX = boundX1 - this.x1 - var boundY = boundX - - var max = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(9), this.imagingHelper.physicalToDataY(9)) - var origin = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(0), this.imagingHelper.physicalToDataY(0)) - var area = (max.x - origin.x) * (max.y - origin.y) - - // var t1 = performance.now() - this.annotations = this.AnnotationStore.getAnnotations(this.x1, this.y1, this.x2, this.y2, area, boundX, boundY, boundX, boundY, function (data) { - self.annotations = data - self.displayGeoAnnots() - self.setupHandlers() - // var t2 = performance.now() - - }) -} + var self = this; + this.x1 = this.imagingHelper._viewportOrigin['x']; + this.y1 = this.imagingHelper._viewportOrigin['y']; + this.x2 = this.x1 + this.imagingHelper._viewportWidth; + this.y2 = this.y1 + this.imagingHelper._viewportHeight; + + boundX1 = this.imagingHelper.physicalToLogicalX(200); + boundY1 = this.imagingHelper.physicalToLogicalY(20); + boundX2 = this.imagingHelper.physicalToLogicalX(20); + boundY2 = this.imagingHelper.physicalToLogicalY(20); + var boundX = boundX1 - this.x1; + var boundY = boundX; + + var max = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(9), this.imagingHelper.physicalToDataY(9)); + var origin = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(0), this.imagingHelper.physicalToDataY(0)); + var area = (max.x - origin.x) * (max.y - origin.y); + + // var t1 = performance.now() + this.annotations = this.AnnotationStore.getAnnotations(this.x1, this.y1, this.x2, this.y2, area, boundX, boundY, boundX, boundY, function (data) { + self.annotations = data; + self.displayGeoAnnots(); + self.setupHandlers() + // var t2 = performance.now() + + }) +}; annotools.prototype.getAnnotFilter = function (author, grade, multi) // Get Annotation from the API { - if (this.initialized) { - this.x1 = this.imagingHelper._viewportOrigin['x'] - this.y1 = this.imagingHelper._viewportOrigin['y'] - this.x2 = this.x1 + this.imagingHelper._viewportWidth - this.y2 = this.y1 + this.imagingHelper._viewportHeight - } - - this.initialized = true - - var jsonRequest = new Request.JSON({ - url: 'api/Data/getAnnotSpatialFilter.php', - onSuccess: function (e) { - if (e == null) this.annotations = [] - else this.annotations = e - this.convertAllToNative() - this.displayAnnot() // Display The Annotations - this.relativeToGlobal() - this.setupHandlers() - // console.log("successfully get annotations") - }.bind(this), - onFailure: function (e) { - this.showMessage('cannot get the annotations,please check your getAnnot function') - this.annotations = [] - }.bind(this) - }).get({ - 'iid': this.iid, - 'x': this.x1, - 'y': this.y1, - 'x1': this.x2, - 'y1': this.y2, - 'author': author, - 'grade': grade, - 'multi': multi - }) -} + if (this.initialized) { + this.x1 = this.imagingHelper._viewportOrigin['x']; + this.y1 = this.imagingHelper._viewportOrigin['y']; + this.x2 = this.x1 + this.imagingHelper._viewportWidth; + this.y2 = this.y1 + this.imagingHelper._viewportHeight + } + + this.initialized = true; + + var jsonRequest = new Request.JSON({ + url: 'api/Data/getAnnotSpatialFilter.php', + onSuccess: function (e) { + if (e == null) this.annotations = []; + else this.annotations = e; + this.convertAllToNative(); + this.displayAnnot(); // Display The Annotations + this.relativeToGlobal(); + this.setupHandlers() + // console.log("successfully get annotations") + }.bind(this), + onFailure: function (e) { + this.showMessage('cannot get the annotations,please check your getAnnot function'); + this.annotations = [] + }.bind(this) + }).get({ + 'iid': this.iid, + 'x': this.x1, + 'y': this.y1, + 'x1': this.x2, + 'y1': this.y2, + 'author': author, + 'grade': grade, + 'multi': multi + }) +}; annotools.prototype.keyPress = function (code) // Key Down Events Handler { - switch (code) { - case 84: - // press t to toggle tools - this.tool.toggle() - break - /* ASHISH Disable quit - case 81: - //press q to quit current mode and return to the default mode - this.quitMode() - this.quitbutton.hide() - break - */ - case 72: - // press white space to toggle annotations - this.toggleMarkups() - break - case 82: - // 1 for rectangle mode - this.mode = 'rect' - this.drawMarkups() - break - case 67: - // 2 for ellipse mode - this.mode = 'ellipse' - this.drawMarkups() - break - case 80: - // 3 for polyline mode - this.mode = 'polyline' - this.drawMarkups() - break - case 70: - // 4 for pencil mode - this.mode = 'pencil' - this.drawMarkups() - break - case 77: - // 5 for measurement mode - this.mode = 'measure' - this.drawMarkups() - break - case 69: - // 6 for magnify mode - this.mode = 'magnify' - this.magnify() - break - } -} + switch (code) { + case 84: + // press t to toggle tools + this.tool.toggle(); + break; + /* ASHISH Disable quit + case 81: + //press q to quit current mode and return to the default mode + this.quitMode() + this.quitbutton.hide() + break + */ + case 72: + // press white space to toggle annotations + this.toggleMarkups(); + break; + case 82: + // 1 for rectangle mode + this.mode = 'rect'; + this.drawMarkups(); + break; + case 67: + // 2 for ellipse mode + this.mode = 'ellipse'; + this.drawMarkups(); + break; + case 80: + // 3 for polyline mode + this.mode = 'polyline'; + this.drawMarkups(); + break; + case 70: + // 4 for pencil mode + this.mode = 'pencil'; + this.drawMarkups(); + break; + case 77: + // 5 for measurement mode + this.mode = 'measure'; + this.drawMarkups(); + break; + case 69: + // 6 for magnify mode + this.mode = 'magnify'; + this.magnify(); + break + } +}; annotools.prototype.drawMarkups = function () // Draw Markups { - this.showMessage() // Show Message - this.drawCanvas.removeEvents('mouseup') - this.drawCanvas.removeEvents('mousedown') - this.drawCanvas.removeEvents('mousemove') - this.drawLayer.show() // Show The Drawing Layer - /* ASHISH Disable quit - this.quitbutton.show() //Show The Quit Button - */ - this.magnifyGlass.hide() // Hide The Magnifying Tool - // this.container = document.id(this.canvas) //Get The Canvas Container - this.container = document.getElementsByClassName(this.canvas)[0] // Get The Canvas Container - // this.container = document.getElementById('container') //Get The Canvas Container - if (this.container) { - // var left = parseInt(this.container.offsetLeft), //Get The Container Location - var left = parseInt(this.container.getLeft()), // Get The Container Location - top = parseInt(this.container.offsetTop), - width = parseInt(this.container.offsetWidth), - height = parseInt(this.container.offsetHeight), - oleft = left, - otop = top, - owidth = width, - oheight = height - - if (left < 0) { - left = 0 - width = window.innerWidth - } // See Whether The Container is outside The Current ViewPort - if (top < 0) { - top = 0 - height = window.innerHeight - } - // Recreate The CreateAnnotation Layer Because of The ViewPort Change Issue. - this.drawLayer.set({ - 'styles': { - left: left, - top: top, - width: width, - height: height - } - }) - // Create Canvas on the CreateAnnotation Layer - this.drawCanvas.set({ - width: width, - height: height - }) - // The canvas context - var ctx = this.drawCanvas.getContext('2d') - // Draw Markups on Canvas - switch (this.mode) { - case 'rect': - this.drawRectangle(ctx) - break - case 'ellipse': - this.drawEllipse(ctx) - break - case 'pencil': - this.drawPencil(ctx) - break - case 'polyline': - this.drawPolyline(ctx) - break - case 'measure': - this.drawMeasure(ctx) - break - } - } else this.showMessage('Container Not SET Correctly Or Not Fully Loaded Yet') -} + this.showMessage(); // Show Message + this.drawCanvas.removeEvents('mouseup'); + this.drawCanvas.removeEvents('mousedown'); + this.drawCanvas.removeEvents('mousemove'); + this.drawLayer.show(); // Show The Drawing Layer + /* ASHISH Disable quit + this.quitbutton.show() //Show The Quit Button + */ + this.magnifyGlass.hide(); // Hide The Magnifying Tool + // this.container = document.id(this.canvas) //Get The Canvas Container + this.container = document.getElementsByClassName(this.canvas)[0]; // Get The Canvas Container + // this.container = document.getElementById('container') //Get The Canvas Container + if (this.container) { + // var left = parseInt(this.container.offsetLeft), //Get The Container Location + var left = parseInt(this.container.getLeft()), // Get The Container Location + top = parseInt(this.container.offsetTop), + width = parseInt(this.container.offsetWidth), + height = parseInt(this.container.offsetHeight), + oleft = left, + otop = top, + owidth = width, + oheight = height; + + if (left < 0) { + left = 0; + width = window.innerWidth + } // See Whether The Container is outside The Current ViewPort + if (top < 0) { + top = 0; + height = window.innerHeight + } + // Recreate The CreateAnnotation Layer Because of The ViewPort Change Issue. + this.drawLayer.set({ + 'styles': { + left: left, + top: top, + width: width, + height: height + } + }); + // Create Canvas on the CreateAnnotation Layer + this.drawCanvas.set({ + width: width, + height: height + }); + // The canvas context + var ctx = this.drawCanvas.getContext('2d'); + // Draw Markups on Canvas + switch (this.mode) { + case 'rect': + this.drawRectangle(ctx); + break; + case 'ellipse': + this.drawEllipse(ctx); + break; + case 'pencil': + this.drawPencil(ctx); + break; + case 'polyline': + this.drawPolyline(ctx); + break; + case 'measure': + this.drawMeasure(ctx); + break + } + } else this.showMessage('Container Not SET Correctly Or Not Fully Loaded Yet') +}; annotools.prototype.createWorkOrder = function () { - this.showMessage() // Show Message - this.drawCanvas.removeEvents('mouseup') - this.drawCanvas.removeEvents('mousedown') - this.drawCanvas.removeEvents('mousemove') - this.drawLayer.show() // Show The Drawing Layer - /* ASHISH Disable quit - this.quitbutton.show() //Show The Quit Button - */ - this.magnifyGlass.hide() // Hide The Magnifying Tool - // this.container = document.id(this.canvas) //Get The Canvas Container - this.container = document.getElementsByClassName(this.canvas)[0] // Get The Canvas Container - // this.container = document.getElementById('container') //Get The Canvas Container - if (this.container) { - // var left = parseInt(this.container.offsetLeft), //Get The Container Location - var left = parseInt(this.container.getLeft()), // Get The Container Location - top = parseInt(this.container.offsetTop), - width = parseInt(this.container.offsetWidth), - height = parseInt(this.container.offsetHeight), - oleft = left, - otop = top, - owidth = width, - oheight = height - - if (left < 0) { - left = 0 - width = window.innerWidth - } // See Whether The Container is outside The Current ViewPort - if (top < 0) { - top = 0 - height = window.innerHeight + this.showMessage(); // Show Message + this.drawCanvas.removeEvents('mouseup'); + this.drawCanvas.removeEvents('mousedown'); + this.drawCanvas.removeEvents('mousemove'); + this.drawLayer.show(); // Show The Drawing Layer + /* ASHISH Disable quit + this.quitbutton.show() //Show The Quit Button + */ + this.magnifyGlass.hide(); // Hide The Magnifying Tool + // this.container = document.id(this.canvas) //Get The Canvas Container + this.container = document.getElementsByClassName(this.canvas)[0]; // Get The Canvas Container + // this.container = document.getElementById('container') //Get The Canvas Container + if (this.container) { + // var left = parseInt(this.container.offsetLeft), //Get The Container Location + var left = parseInt(this.container.getLeft()), // Get The Container Location + top = parseInt(this.container.offsetTop), + width = parseInt(this.container.offsetWidth), + height = parseInt(this.container.offsetHeight), + oleft = left, + otop = top, + owidth = width, + oheight = height; + + if (left < 0) { + left = 0; + width = window.innerWidth + } // See Whether The Container is outside The Current ViewPort + if (top < 0) { + top = 0; + height = window.innerHeight + } + // Recreate The CreateAnnotation Layer Because of The ViewPort Change Issue. + this.drawLayer.set({ + 'styles': { + left: left, + top: top, + width: width, + height: height + } + }); + // Create Canvas on the CreateAnnotation Layer + this.drawCanvas.set({ + width: width, + height: height + }); + // The canvas context + var ctx = this.drawCanvas.getContext('2d'); + + + this.removeMouseEvents(); + var started = false; + var min_x, min_y, max_x, max_y, w, h; + var startPosition; + this.drawCanvas.addEvent('mousedown', function (e) { + started = true; + startPosition = OpenSeadragon.getMousePosition(e.event); + x = startPosition.x; + y = startPosition.y + }); + + this.drawCanvas.addEvent('mousemove', function (e) { + if (started) { + ctx.clearRect(0, 0, this.drawCanvas.width, this.drawCanvas.height); + var currentMousePosition = OpenSeadragon.getMousePosition(e.event); + + min_x = Math.min(currentMousePosition.x, startPosition.x); + min_y = Math.min(currentMousePosition.y, startPosition.y); + max_x = Math.max(currentMousePosition.x, startPosition.x); + max_y = Math.max(currentMousePosition.y, startPosition.y); + w = Math.abs(max_x - min_x); + h = Math.abs(max_y - min_y); + ctx.strokeStyle = this.color; + ctx.fillStyle = 'rgba(255, 255, 255, 0.2)'; + ctx.fillRect(min_x, min_y, w, h); + ctx.strokeRect(min_x, min_y, w, h) + } + }.bind(this)); + + this.drawCanvas.addEvent('mouseup', function (e) { + started = false; + var finalMousePosition = new OpenSeadragon.getMousePosition(e.event); + + min_x = Math.min(finalMousePosition.x, startPosition.x); + min_y = Math.min(finalMousePosition.y, startPosition.y); + max_x = Math.max(finalMousePosition.x, startPosition.x); + max_y = Math.max(finalMousePosition.y, startPosition.y); + + var startRelativeMousePosition = new OpenSeadragon.Point(min_x, min_y).minus(OpenSeadragon.getElementOffset(viewer.canvas)); + var endRelativeMousePosition = new OpenSeadragon.Point(max_x, max_y).minus(OpenSeadragon.getElementOffset(viewer.canvas)); + var newAnnot = { + x: startRelativeMousePosition.x, + y: startRelativeMousePosition.y, + w: w, + h: h, + type: 'rect', + color: this.color, + loc: [] + }; + + var globalNumbers = JSON.parse(this.convertFromNative(newAnnot, endRelativeMousePosition)); + + newAnnot.x = globalNumbers.nativeX; + newAnnot.y = globalNumbers.nativeY; + newAnnot.w = globalNumbers.nativeW; + newAnnot.h = globalNumbers.nativeH; + var loc = []; + loc[0] = parseFloat(newAnnot.x); + loc[1] = parseFloat(newAnnot.y); + newAnnot.loc = loc; + + // convert to geojson + // var geoNewAnnot = this.convertRectToGeo(newAnnot) + geoNewAnnot = newAnnot; + this.promptForWorkOrder(geoNewAnnot, 'new', this, ctx) + }.bind(this)) } - // Recreate The CreateAnnotation Layer Because of The ViewPort Change Issue. - this.drawLayer.set({ - 'styles': { - left: left, - top: top, - width: width, - height: height - } - }) - // Create Canvas on the CreateAnnotation Layer - this.drawCanvas.set({ - width: width, - height: height - }) - // The canvas context - var ctx = this.drawCanvas.getContext('2d') - - - this.removeMouseEvents() - var started = false - var min_x,min_y,max_x,max_y,w,h - var startPosition - this.drawCanvas.addEvent('mousedown', function (e) { - started = true - startPosition = OpenSeadragon.getMousePosition(e.event) - x = startPosition.x - y = startPosition.y - }) - - this.drawCanvas.addEvent('mousemove', function (e) { - if (started) { - ctx.clearRect(0, 0, this.drawCanvas.width, this.drawCanvas.height) - var currentMousePosition = OpenSeadragon.getMousePosition(e.event) - - min_x = Math.min(currentMousePosition.x, startPosition.x) - min_y = Math.min(currentMousePosition.y, startPosition.y) - max_x = Math.max(currentMousePosition.x, startPosition.x) - max_y = Math.max(currentMousePosition.y, startPosition.y) - w = Math.abs(max_x - min_x) - h = Math.abs(max_y - min_y) - ctx.strokeStyle = this.color - ctx.fillStyle = 'rgba(255, 255, 255, 0.2)' - ctx.fillRect(min_x, min_y, w, h) - ctx.strokeRect(min_x, min_y, w, h) - } - }.bind(this)) - - this.drawCanvas.addEvent('mouseup', function (e) { - started = false - var finalMousePosition = new OpenSeadragon.getMousePosition(e.event) - - min_x = Math.min(finalMousePosition.x, startPosition.x) - min_y = Math.min(finalMousePosition.y, startPosition.y) - max_x = Math.max(finalMousePosition.x, startPosition.x) - max_y = Math.max(finalMousePosition.y, startPosition.y) - - var startRelativeMousePosition = new OpenSeadragon.Point(min_x, min_y).minus(OpenSeadragon.getElementOffset(viewer.canvas)) - var endRelativeMousePosition = new OpenSeadragon.Point(max_x, max_y).minus(OpenSeadragon.getElementOffset(viewer.canvas)) - var newAnnot = { - x: startRelativeMousePosition.x, - y: startRelativeMousePosition.y, - w: w, - h: h, - type: 'rect', - color: this.color, - loc: [] - } - - var globalNumbers = JSON.parse(this.convertFromNative(newAnnot, endRelativeMousePosition)) - - newAnnot.x = globalNumbers.nativeX - newAnnot.y = globalNumbers.nativeY - newAnnot.w = globalNumbers.nativeW - newAnnot.h = globalNumbers.nativeH - var loc = [] - loc[0] = parseFloat(newAnnot.x) - loc[1] = parseFloat(newAnnot.y) - newAnnot.loc = loc - - // convert to geojson - // var geoNewAnnot = this.convertRectToGeo(newAnnot) - geoNewAnnot = newAnnot - this.promptForWorkOrder(geoNewAnnot, 'new', this, ctx) - }.bind(this)) - } -} +}; annotools.prototype.magnify = function () // Magnify Tool { - /* ASHISH Disable quit - this.quitbutton.show() - */ - this.drawLayer.hide() - this.magnifyGlass.hide() - this.magnifyGlass.set({ - html: '' - }) - var content = new Element('div', { - 'class': 'magnified_content', - styles: { - width: document.getSize().x, - height: document.getSize().y - } - }) - content.set({ - html: document.body.innerHTML - }) - content.inject(this.magnifyGlass) - var scale = 2.0 - var left = parseInt(this.magnifyGlass.style.left) - var top = parseInt(this.magnifyGlass.style.top) - this.magnifyGlass.set({ - 'styles': { - left: left, - top: top - } - }) - content.set({ - 'styles': { - left: -scale * left, - top: -scale * top - } - }) - this.magnifyGlass.show() - this.magnifyGlass.makeDraggable({ - onDrag: function (draggable) { - this.showMessage('drag the magnifying glass') - var left = parseInt(this.magnifyGlass.style.left) - var top = parseInt(this.magnifyGlass.style.top) - this.magnifyGlass.set({ + /* ASHISH Disable quit + this.quitbutton.show() + */ + this.drawLayer.hide(); + this.magnifyGlass.hide(); + this.magnifyGlass.set({ + html: '' + }); + var content = new Element('div', { + 'class': 'magnified_content', + styles: { + width: document.getSize().x, + height: document.getSize().y + } + }); + content.set({ + html: document.body.innerHTML + }); + content.inject(this.magnifyGlass); + var scale = 2.0; + var left = parseInt(this.magnifyGlass.style.left); + var top = parseInt(this.magnifyGlass.style.top); + this.magnifyGlass.set({ 'styles': { - left: left, - top: top + left: left, + top: top } - }) - content.set({ + }); + content.set({ 'styles': { - left: -scale * left, - top: -scale * top + left: -scale * left, + top: -scale * top } - }) - }.bind(this) - /*ASHISH DIsable quit - ,onDrop: function (draggable) { - this.showMessage("Press q to quit") - }.bind(this) - */ - }) -} + }); + this.magnifyGlass.show(); + this.magnifyGlass.makeDraggable({ + onDrag: function (draggable) { + this.showMessage('drag the magnifying glass'); + var left = parseInt(this.magnifyGlass.style.left); + var top = parseInt(this.magnifyGlass.style.top); + this.magnifyGlass.set({ + 'styles': { + left: left, + top: top + } + }); + content.set({ + 'styles': { + left: -scale * left, + top: -scale * top + } + }) + }.bind(this) + /*ASHISH DIsable quit + ,onDrop: function (draggable) { + this.showMessage("Press q to quit") + }.bind(this) + */ + }) +}; annotools.prototype.selectColor = function () // Pick A Color { - this.colorContainer = new Element('div').inject(this.tool) - var blackColor = new Element('img', { - 'class': 'colorButton', - 'title': 'black', - 'styles': { - 'background-color': 'black' - }, - 'events': { - 'click': function () { - this.color = 'black' - this.colorContainer.destroy() - }.bind(this) - } - }).inject(this.colorContainer) - var redColor = new Element('img', { - 'class': 'colorButton', - 'title': 'Default', - 'styles': { - 'background-color': 'red' - }, - 'events': { - 'click': function () { - this.color = 'red' - this.colorContainer.destroy() - }.bind(this) - } - }).inject(this.colorContainer) - var blueColor = new Element('img', { - 'class': 'colorButton', - 'title': 'blue', - 'styles': { - 'background-color': 'blue' - }, - 'events': { - 'click': function () { - this.color = 'blue' - this.colorContainer.destroy() - }.bind(this) - } - }).inject(this.colorContainer) - var greenColor = new Element('img', { - 'class': 'colorButton', - 'title': 'lime', - 'styles': { - 'background-color': 'lime' - }, - 'events': { - 'click': function () { - this.color = 'lime' - this.colorContainer.destroy() - }.bind(this) - } - }).inject(this.colorContainer) - var purpleColor = new Element('img', { - 'class': 'colorButton', - 'title': 'purple', - 'styles': { - 'background-color': 'purple' - }, - 'events': { - 'click': function () { - this.color = 'purple' - this.colorContainer.destroy() - }.bind(this) - } - }).inject(this.colorContainer) - var orangeColor = new Element('img', { - 'class': 'colorButton', - 'title': 'orange', - 'styles': { - 'background-color': 'orange' - }, - 'events': { - 'click': function () { - this.color = 'orange' - this.colorContainer.destroy() - }.bind(this) - } - }).inject(this.colorContainer) - var yellowColor = new Element('img', { - 'class': 'colorButton', - 'title': 'yellow', - 'styles': { - 'background-color': 'yellow' - }, - 'events': { - 'click': function () { - this.color = 'yellow' - this.colorContainer.destroy() - }.bind(this) - } - }).inject(this.colorContainer) - var pinkColor = new Element('img', { - 'class': 'colorButton', - 'title': 'pink', - 'styles': { - 'background-color': 'pink' - }, - 'events': { - 'click': function () { - this.color = 'pink' - this.colorContainer.destroy() - }.bind(this) + this.colorContainer = new Element('div').inject(this.tool); + var blackColor = new Element('img', { + 'class': 'colorButton', + 'title': 'black', + 'styles': { + 'background-color': 'black' + }, + 'events': { + 'click': function () { + this.color = 'black'; + this.colorContainer.destroy() + }.bind(this) + } + }).inject(this.colorContainer); + var redColor = new Element('img', { + 'class': 'colorButton', + 'title': 'Default', + 'styles': { + 'background-color': 'red' + }, + 'events': { + 'click': function () { + this.color = 'red'; + this.colorContainer.destroy() + }.bind(this) + } + }).inject(this.colorContainer); + var blueColor = new Element('img', { + 'class': 'colorButton', + 'title': 'blue', + 'styles': { + 'background-color': 'blue' + }, + 'events': { + 'click': function () { + this.color = 'blue'; + this.colorContainer.destroy() + }.bind(this) + } + }).inject(this.colorContainer); + var greenColor = new Element('img', { + 'class': 'colorButton', + 'title': 'lime', + 'styles': { + 'background-color': 'lime' + }, + 'events': { + 'click': function () { + this.color = 'lime'; + this.colorContainer.destroy() + }.bind(this) + } + }).inject(this.colorContainer); + var purpleColor = new Element('img', { + 'class': 'colorButton', + 'title': 'purple', + 'styles': { + 'background-color': 'purple' + }, + 'events': { + 'click': function () { + this.color = 'purple'; + this.colorContainer.destroy() + }.bind(this) + } + }).inject(this.colorContainer); + var orangeColor = new Element('img', { + 'class': 'colorButton', + 'title': 'orange', + 'styles': { + 'background-color': 'orange' + }, + 'events': { + 'click': function () { + this.color = 'orange'; + this.colorContainer.destroy() + }.bind(this) + } + }).inject(this.colorContainer); + var yellowColor = new Element('img', { + 'class': 'colorButton', + 'title': 'yellow', + 'styles': { + 'background-color': 'yellow' + }, + 'events': { + 'click': function () { + this.color = 'yellow'; + this.colorContainer.destroy() + }.bind(this) + } + }).inject(this.colorContainer); + var pinkColor = new Element('img', { + 'class': 'colorButton', + 'title': 'pink', + 'styles': { + 'background-color': 'pink' + }, + 'events': { + 'click': function () { + this.color = 'pink'; + this.colorContainer.destroy() + }.bind(this) + } + }).inject(this.colorContainer); + var colorButtons = document.getElements('.colorButton'); + for (var i = 0; i < colorButtons.length; i++) { + colorButtons[i].addEvents({ + 'mouseenter': function () { + this.addClass('selected') + }, + 'mouseleave': function () { + this.removeClass('selected') + } + }) } - }).inject(this.colorContainer) - var colorButtons = document.getElements('.colorButton') - for (var i = 0; i < colorButtons.length; i++) { - colorButtons[i].addEvents({ - 'mouseenter': function () { - this.addClass('selected') - }, - 'mouseleave': function () { - this.removeClass('selected') - } - }) - } -} +}; annotools.prototype.addnewAnnot = function (newAnnot) // Add New Annotations { - // console.log(this) - // newAnnot.iid = this.iid - // newAnnot.annotIdi = MD5(new Date().toString()) - // console.log(newAnnot) - // this.annotations.push(newAnnot) - // console.log(this.annotations) - console.log(newAnnot) - this.saveAnnot(newAnnot); - console.log("saved annotation") - if(this.toolBar.mode == 'merge_step2'){ - //if(this.save_success == "yes"){ - this.deleteAnnotationWithinRectangle(newAnnot); - console.log("deleteAnnotationWithinRectangle") - //} - } - this.displayGeoAnnots() -} + // console.log(this) + // newAnnot.iid = this.iid + // newAnnot.annotIdi = MD5(new Date().toString()) + // console.log(newAnnot) + // this.annotations.push(newAnnot) + // console.log(this.annotations) + console.log(newAnnot); + this.saveAnnot(newAnnot); + console.log("saved annotation"); + if (this.toolBar.mode == 'merge_step2') { + //if(this.save_success == "yes"){ + this.deleteAnnotationWithinRectangle(newAnnot); + console.log("deleteAnnotationWithinRectangle") + //} + } + this.displayGeoAnnots() +}; annotools.prototype.toggleMarkups = function () // Toggle Markups { - if (this.svg) { - if (this.annotVisible) { - this.annotVisible = false - this.svg.hide() - document.getElements('.annotcontainer').hide() + if (this.svg) { + if (this.annotVisible) { + this.annotVisible = false; + this.svg.hide(); + document.getElements('.annotcontainer').hide() + } else { + this.annotVisible = true; + this.displayGeoAnnots(); + document.getElements('.annotcontainer').show() + } } else { - this.annotVisible = true - this.displayGeoAnnots() - document.getElements('.annotcontainer').show() - } - } else { - this.annotVisible = true + this.annotVisible = true; - this.displayGeoAnnots() - } - this.showMessage('annotation toggled') -} + this.displayGeoAnnots() + } + this.showMessage('annotation toggled') +}; annotools.prototype.showMessage = function (msg) // Show Messages { - /*ASHISH DIsable quit - if (!(msg)) msg = this.mode + " mode,press q to quit" - */ - this.messageBox.set({ - html: msg - }) - var myFx = new Fx.Tween('messageBox', { - duration: 'long', - transition: 'bounce:out', - link: 'cancel', - property: 'opacity' - }).start(0, 1).chain(function () { - this.start(0.5, 0) - }) -} + /*ASHISH DIsable quit + if (!(msg)) msg = this.mode + " mode,press q to quit" + */ + this.messageBox.set({ + html: msg + }); + var myFx = new Fx.Tween('messageBox', { + duration: 'long', + transition: 'bounce:out', + link: 'cancel', + property: 'opacity' + }).start(0, 1).chain(function () { + this.start(0.5, 0) + }) +}; annotools.prototype.relativeToGlobal = function () { - for (var i = 0; i < $('viewport').getChildren().length; i++) { - var object = $('viewport').getChildren()[i] - - if (object.tagName == 'ellipse') { - var originalCoord = {} - console.log('relativeToGlobal: ' + viewer.viewport.getZoom() + ' ' + this.annotationHandler.zoomBase) - originalCoord.cx = object.getAttribute('cx') - originalCoord.cy = object.getAttribute('cy') - if (viewer.viewport.getZoom() != this.annotationHandler.zoomBase) { - originalCoord.rx = object.getAttribute('rx') * this.annotationHandler.zoomBase - originalCoord.ry = object.getAttribute('ry') * this.annotationHandler.zoomBase - } else { - originalCoord.rx = object.getAttribute('rx') - originalCoord.ry = object.getAttribute('ry') - } - originalCoord.zoom = viewer.viewport.getZoom() - this.annotationHandler.originalCoords[object.id] = originalCoord - var bbox = object.getBBox() - - var objectCenterPt = new OpenSeadragon.Point(bbox.x + bbox.width / 2, bbox.y + bbox.height / 2) - var objectCenterRelPt = this.viewer.viewport.pointFromPixel(objectCenterPt) - - // SBA - originalCoord.cx = objectCenterRelPt.x - originalCoord.cy = objectCenterRelPt.y - - this.annotationHandler.objectCenterPts[i] = objectCenterRelPt - } else if (object.tagName == 'rect') { - var originalCoord = {} - originalCoord.x = object.getAttribute('x') - originalCoord.y = object.getAttribute('y') - originalCoord.width = object.getAttribute('width') - originalCoord.height = object.getAttribute('height') - originalCoord.zoom = viewer.viewport.getZoom() - this.annotationHandler.originalCoords[object.id] = originalCoord - var bbox = object.getBBox() - var objectCenterPt = new OpenSeadragon.Point(bbox.x + bbox.width / 2, bbox.y + bbox.height / 2) - var objectCenterRelPt = this.viewer.viewport.pointFromPixel(objectCenterPt) - this.annotationHandler.objectCenterPts[i] = objectCenterRelPt - }else { - var bbox = object.getBBox() - var objectCenterPt = - new OpenSeadragon.Point( - bbox.x + bbox.width / 2, - bbox.y + bbox.height / 2 - ) - console.log('bbox: ' + bbox) - var objectCenterRelPt = - this.viewer.viewport.pointFromPixel(objectCenterPt) - this.annotationHandler.objectCenterPts[i] = objectCenterRelPt - var originalCoord = {} - originalCoord.cx = objectCenterPt.x - originalCoord.cy = objectCenterPt.y - var points = - String.split(object.getAttribute('points').trim(), ' ') - - var distances = [] - for (var j = 0; j < points.length; j++) { - var pointPair = String.split(points[j], ',') - var point = - new OpenSeadragon.Point( - parseFloat(pointPair[0]), - parseFloat(pointPair[1]) - ) - var relPt = this.viewer.viewport.pointFromPixel(point) - var dist = relPt.minus(objectCenterRelPt) - distances.push(dist) - } - - this.annotationHandler.originalCoords[object.id] = { - center: objectCenterRelPt, - distances: distances} + for (var i = 0; i < $('viewport').getChildren().length; i++) { + var object = $('viewport').getChildren()[i]; + + if (object.tagName == 'ellipse') { + var originalCoord = {}; + console.log('relativeToGlobal: ' + viewer.viewport.getZoom() + ' ' + this.annotationHandler.zoomBase); + originalCoord.cx = object.getAttribute('cx'); + originalCoord.cy = object.getAttribute('cy'); + if (viewer.viewport.getZoom() != this.annotationHandler.zoomBase) { + originalCoord.rx = object.getAttribute('rx') * this.annotationHandler.zoomBase; + originalCoord.ry = object.getAttribute('ry') * this.annotationHandler.zoomBase + } else { + originalCoord.rx = object.getAttribute('rx'); + originalCoord.ry = object.getAttribute('ry') + } + originalCoord.zoom = viewer.viewport.getZoom(); + this.annotationHandler.originalCoords[object.id] = originalCoord; + var bbox = object.getBBox(); + + var objectCenterPt = new OpenSeadragon.Point(bbox.x + bbox.width / 2, bbox.y + bbox.height / 2); + var objectCenterRelPt = this.viewer.viewport.pointFromPixel(objectCenterPt); + + // SBA + originalCoord.cx = objectCenterRelPt.x; + originalCoord.cy = objectCenterRelPt.y; + + this.annotationHandler.objectCenterPts[i] = objectCenterRelPt + } else if (object.tagName == 'rect') { + var originalCoord = {}; + originalCoord.x = object.getAttribute('x'); + originalCoord.y = object.getAttribute('y'); + originalCoord.width = object.getAttribute('width'); + originalCoord.height = object.getAttribute('height'); + originalCoord.zoom = viewer.viewport.getZoom(); + this.annotationHandler.originalCoords[object.id] = originalCoord; + var bbox = object.getBBox(); + var objectCenterPt = new OpenSeadragon.Point(bbox.x + bbox.width / 2, bbox.y + bbox.height / 2); + var objectCenterRelPt = this.viewer.viewport.pointFromPixel(objectCenterPt); + this.annotationHandler.objectCenterPts[i] = objectCenterRelPt + } else { + var bbox = object.getBBox(); + var objectCenterPt = + new OpenSeadragon.Point( + bbox.x + bbox.width / 2, + bbox.y + bbox.height / 2 + ); + console.log('bbox: ' + bbox); + var objectCenterRelPt = + this.viewer.viewport.pointFromPixel(objectCenterPt); + this.annotationHandler.objectCenterPts[i] = objectCenterRelPt; + var originalCoord = {}; + originalCoord.cx = objectCenterPt.x; + originalCoord.cy = objectCenterPt.y; + var points = + String.split(object.getAttribute('points').trim(), ' '); + + var distances = []; + for (var j = 0; j < points.length; j++) { + var pointPair = String.split(points[j], ','); + var point = + new OpenSeadragon.Point( + parseFloat(pointPair[0]), + parseFloat(pointPair[1]) + ); + var relPt = this.viewer.viewport.pointFromPixel(point); + var dist = relPt.minus(objectCenterRelPt); + distances.push(dist) + } + + this.annotationHandler.originalCoords[object.id] = { + center: objectCenterRelPt, + distances: distances + } + } } - } -} +}; annotools.prototype.setupHandlers = function () { - //console.log('setting up handlers') - - var root = document.getElementsByTagName('svg')[0] - // console.log(root); - if (root != undefined) { - if (navigator.userAgent.toLowerCase().indexOf('webkit') >= 0) { - window.addEventListener('mousewheel', this.annotationHandler.handleMouseWheel, false) // Chrome/Safari - // window.addEventListener('mousewheel', this.getAnnot(), false) // Chrome/Safari - } else { - window.addEventListener('DOMMouseScroll', this.annotationHandler.handleMouseWheel, false) // Others - // window.addEventListener('DOMMouseScroll', this.getAnnot(), false) // Others + //console.log('setting up handlers') + + var root = document.getElementsByTagName('svg')[0]; + // console.log(root); + if (root != undefined) { + if (navigator.userAgent.toLowerCase().indexOf('webkit') >= 0) { + window.addEventListener('mousewheel', this.annotationHandler.handleMouseWheel, false) // Chrome/Safari + // window.addEventListener('mousewheel', this.getAnnot(), false) // Chrome/Safari + } else { + window.addEventListener('DOMMouseScroll', this.annotationHandler.handleMouseWheel, false) // Others + // window.addEventListener('DOMMouseScroll', this.getAnnot(), false) // Others + } + // console.log(root) + this.addMouseEvents() } - // console.log(root) - this.addMouseEvents() - } - // console.log("...") - for (var i = 0; i < this.viewer.buttons.buttons.length; i++) { - var button = this.viewer.buttons.buttons[i] - - if (button.tooltip.toLowerCase() == 'go home') { - var onHomeRelease = button.onRelease - var annot = this - button.onRelease = function (args) { - $$('svg')[0].setStyle('opacity', 0) - onHomeRelease(args) - setTimeout(annotationHandler.goHome, annotationHandler.animateWaitTime, annot) - } + // console.log("...") + for (var i = 0; i < this.viewer.buttons.buttons.length; i++) { + var button = this.viewer.buttons.buttons[i]; + + if (button.tooltip.toLowerCase() == 'go home') { + var onHomeRelease = button.onRelease; + var annot = this; + button.onRelease = function (args) { + $$('svg')[0].setStyle('opacity', 0); + onHomeRelease(args); + setTimeout(annotationHandler.goHome, annotationHandler.animateWaitTime, annot) + } + } } - } -} +}; annotools.prototype.displayTip = function (id) // Display Tips { - // var container = document.id(this.canvas) - var container = document.getElementsByClassName(this.canvas)[0] // Get The Canvas Container - var width = parseInt(container.offsetWidth), - height = parseInt(container.offsetHeight), - annot = this.annotations[id] - var d = new Element('div', { - 'class': 'annotip', - styles: { - position: 'absolute', - left: Math.round(width * annot.x), - top: Math.round(height * annot.y) - }, - html: annot.text - }).inject(container) - this.showMessage('Double Click to Edit') -} + // var container = document.id(this.canvas) + var container = document.getElementsByClassName(this.canvas)[0]; // Get The Canvas Container + var width = parseInt(container.offsetWidth), + height = parseInt(container.offsetHeight), + annot = this.annotations[id]; + var d = new Element('div', { + 'class': 'annotip', + styles: { + position: 'absolute', + left: Math.round(width * annot.x), + top: Math.round(height * annot.y) + }, + html: annot.text + }).inject(container); + this.showMessage('Double Click to Edit') +}; annotools.prototype.destroyTip = function () // Destroy Tips { - // var container = document.id(this.canvas) - var container = document.getElementsByClassName(this.canvas)[0] // Get The Canvas Container - container.getElements('.annotip').destroy() -} + // var container = document.id(this.canvas) + var container = document.getElementsByClassName(this.canvas)[0]; // Get The Canvas Container + container.getElements('.annotip').destroy() +}; annotools.prototype.editTip = function (id) // Edit Tips { - this.removeMouseEvents() - var annotools = this - var annotation = this.annotations[id] - var annotationTextJson = annotation.text - var content = '' - for (var key in annotationTextJson) { - content += "

" + key + ': ' + annotationTextJson[key] + '

' - } - content += "

Created by: " + this.annotations[id].username + '

' - var SM = new SimpleModal() - SM.addButton('Edit Annotation', 'btn primary', function () { - annotools.promptForAnnotation(annotation, 'edit', annotools, null) - }) - SM.addButton('Edit Markup', 'btn primary', function () { - annotools.addMouseEvents() - this.hide() - }) - SM.addButton('Delete', 'btn primary', function () { - var NSM = new SimpleModal() - NSM.addButton('Confirm', 'btn primary', function () { - annotools.deleteAnnot(id) - annotools.addMouseEvents() - this.hide() - }) - NSM.addButton('Cancel', 'btn cancel', function () { - annotools.addMouseEvents() - this.hide() - }) - NSM.show({ - 'model': 'modal', - 'title': 'Confirm deletion', - 'contents': 'Are you sure you want to delete this annotation?' + this.removeMouseEvents(); + var annotools = this; + var annotation = this.annotations[id]; + var annotationTextJson = annotation.text; + var content = ''; + for (var key in annotationTextJson) { + content += "

" + key + ': ' + annotationTextJson[key] + '

' + } + content += "

Created by: " + this.annotations[id].username + '

'; + var SM = new SimpleModal(); + SM.addButton('Edit Annotation', 'btn primary', function () { + annotools.promptForAnnotation(annotation, 'edit', annotools, null) + }); + SM.addButton('Edit Markup', 'btn primary', function () { + annotools.addMouseEvents(); + this.hide() + }); + SM.addButton('Delete', 'btn primary', function () { + var NSM = new SimpleModal(); + NSM.addButton('Confirm', 'btn primary', function () { + annotools.deleteAnnot(id); + annotools.addMouseEvents(); + this.hide() + }); + NSM.addButton('Cancel', 'btn cancel', function () { + annotools.addMouseEvents(); + this.hide() + }); + NSM.show({ + 'model': 'modal', + 'title': 'Confirm deletion', + 'contents': 'Are you sure you want to delete this annotation?' + }) + }); + SM.addButton('Cancel', 'btn secondary', function () { + annotools.addMouseEvents(); + this.hide() + }); + SM.show({ + 'model': 'modal', + 'title': 'Annotation', + 'contents': content }) - }) - SM.addButton('Cancel', 'btn secondary', function () { - annotools.addMouseEvents() - this.hide() - }) - SM.show({ - 'model': 'modal', - 'title': 'Annotation', - 'contents': content - }) -} +}; annotools.prototype.deleteAnnot = function (id) // Delete Annotations { - var testAnnotId = this.annotations[id].annotId - this.annotations.splice(id, 1) - // ########### Do the delete using bindaas instead of on local list. - if (this.iid) { - var jsonRequest = new Request.JSON({ - url: 'api/Data/deleteAnnot.php', - async: false, - onSuccess: function (e) { - this.showMessage('deleted from server') - }.bind(this), - onFailure: function (e) { - this.showMessage('Error deleting the Annotations, please check your deleteAnnot php') - } - .bind(this)} - ).get({'annotId': testAnnotId}) - } - this.displayAnnot() -} + var testAnnotId = this.annotations[id].annotId; + this.annotations.splice(id, 1); + // ########### Do the delete using bindaas instead of on local list. + if (this.iid) { + var jsonRequest = new Request.JSON({ + url: 'api/Data/deleteAnnot.php', + async: false, + onSuccess: function (e) { + this.showMessage('deleted from server') + }.bind(this), + onFailure: function (e) { + this.showMessage('Error deleting the Annotations, please check your deleteAnnot php') + } + .bind(this) + } + ).get({'annotId': testAnnotId}) + } + this.displayAnnot() +}; annotools.prototype.updateAnnot = function (annot) // Save Annotations { - var jsonRequest = new Request.JSON({ - url: 'api/Data/updateAnnot.php', - onSuccess: function (e) { - this.showMessage('saved to the server') - }.bind(this), - onFailure: function (e) { - this.showMessage('Error Saving the Annotations,please check you saveAnnot funciton') - }.bind(this) - }).post({ - 'iid': this.iid, - 'annot': annot - }) - this.displayAnnot() -} + var jsonRequest = new Request.JSON({ + url: 'api/Data/updateAnnot.php', + onSuccess: function (e) { + this.showMessage('saved to the server') + }.bind(this), + onFailure: function (e) { + this.showMessage('Error Saving the Annotations,please check you saveAnnot funciton') + }.bind(this) + }).post({ + 'iid': this.iid, + 'annot': annot + }); + this.displayAnnot() +}; annotools.prototype.saveAnnot = function (annotation) // Save Annotations { - console.log("Save Annotations"); - var self = this; - this.save_success="no"; - console.log('Save annotation function') - console.log(annotation) - //add first vertice to the end of loop to ensure the polygon is closed - var total_points= annotation.geometry.coordinates[0].length; - var fpoint_x=annotation.geometry.coordinates[0][0][0]; - var fpoint_y=annotation.geometry.coordinates[0][0][1]; - var lpoint_x=annotation.geometry.coordinates[0][total_points-1][0]; - var lpoint_y=annotation.geometry.coordinates[0][total_points-1][1]; - - if(fpoint_x!=lpoint_x || fpoint_y!=lpoint_y){ - annotation.geometry.coordinates[0].push([]); - annotation.geometry.coordinates[0][total_points].push(fpoint_x); - annotation.geometry.coordinates[0][total_points].push(fpoint_y); - } - - // get algorithm and color info - var algo_and_color = this.getAlgorithmColorFromMenuTree(); - if (algo_and_color === null) { - return false; - } - else { - var selected_algorithm = algo_and_color.algorithm; - var selected_color = algo_and_color.color; - } - - var user=annotool.user; - var d = new Date(); - var current_time=d.toLocaleString(); - - annotation.color=selected_color; - annotation.algorithm=selected_algorithm; - annotation.created_by=user; - annotation.created_on=current_time; - annotation.updated_by=''; - annotation.updated_on=''; - - - jQuery.ajax({ - 'type': 'POST', - url: 'api/Data/getAnnotSpatial_sc.php', - data: annotation, - success: function (res, err) { - console.log("response: ") - console.log(res) - if(res == "unauthorized"){ - alert("Error saving markup! Wrong secret"); - } else { - alert("Successfully saved markup!"); - } - console.log(err) - self.getMultiAnnot(); - console.log('succesfully posted'); - this.save_success="yes"; + console.log("Save Annotations"); + var self = this; + this.save_success = "no"; + console.log('Save annotation function'); + console.log(annotation); + //add first vertice to the end of loop to ensure the polygon is closed + var total_points = annotation.geometry.coordinates[0].length; + var fpoint_x = annotation.geometry.coordinates[0][0][0]; + var fpoint_y = annotation.geometry.coordinates[0][0][1]; + var lpoint_x = annotation.geometry.coordinates[0][total_points - 1][0]; + var lpoint_y = annotation.geometry.coordinates[0][total_points - 1][1]; + + if (fpoint_x != lpoint_x || fpoint_y != lpoint_y) { + annotation.geometry.coordinates[0].push([]); + annotation.geometry.coordinates[0][total_points].push(fpoint_x); + annotation.geometry.coordinates[0][total_points].push(fpoint_y); } - }) -} + + // get algorithm and color info + var algo_and_color = this.getAlgorithmColorFromMenuTree(); + if (algo_and_color === null) { + return false; + } + else { + var selected_algorithm = algo_and_color.algorithm; + var selected_color = algo_and_color.color; + } + + var user = annotool.user; + var d = new Date(); + var current_time = d.toLocaleString(); + + annotation.color = selected_color; + annotation.algorithm = selected_algorithm; + annotation.created_by = user; + annotation.created_on = current_time; + annotation.updated_by = ''; + annotation.updated_on = ''; + + + jQuery.ajax({ + 'type': 'POST', + url: 'api/Data/getAnnotSpatial_sc.php', + data: annotation, + success: function (res, err) { + console.log("response: "); + console.log(res); + if (res == "unauthorized") { + alert("Error saving markup! Wrong secret"); + } else { + alert("Successfully saved markup!"); + } + console.log(err); + self.getMultiAnnot(); + console.log('succesfully posted'); + this.save_success = "yes"; + } + }) +}; annotools.prototype.convertToNative = function (annot) { - if (annot.type == 'rect' || annot.type == 'ellipse') { - var x = annot.x - var y = annot.y - var w = annot.w - var h = annot.h - - var nativeW = this.imagingHelper.logicalToPhysicalDistance(w) - var nativeH = this.imagingHelper.logicalToPhysicalDistance(h) - var nativeX = this.imagingHelper.logicalToPhysicalX(x) - var nativeY = this.imagingHelper.logicalToPhysicalY(y) - var nativeNumbers = JSON.encode({nativeW: nativeW,nativeH: nativeH,nativeX: nativeX,nativeY: nativeY}) - return nativeNumbers - } - - else if (annot.type == 'polyline' || annot.type == 'pencil' || annot.type == 'line') { - var x = annot.x - var y = annot.y - var w = annot.w - var h = annot.h - var point = annot.points - - var nativeW = this.imagingHelper.logicalToPhysicalDistance(w) - var nativeH = this.imagingHelper.logicalToPhysicalDistance(h) - var nativeX = this.imagingHelper.logicalToPhysicalX(x) - var nativeY = this.imagingHelper.logicalToPhysicalY(y) - - var poly_first_split = String.split(point, ' ') - var points = '' - for (var k = 0; k < poly_first_split.length - 1; k++) { - var poly_second_split = String.split(poly_first_split[k], ',') - - var polyPoint = new OpenSeadragon.Point(parseFloat(poly_second_split[0]), parseFloat(poly_second_split[1])) - - points += this.imagingHelper.logicalToPhysicalX(polyPoint.x) + ',' + this.imagingHelper.logicalToPhysicalY(polyPoint.y) + ' ' + if (annot.type == 'rect' || annot.type == 'ellipse') { + var x = annot.x; + var y = annot.y; + var w = annot.w; + var h = annot.h; + + var nativeW = this.imagingHelper.logicalToPhysicalDistance(w); + var nativeH = this.imagingHelper.logicalToPhysicalDistance(h); + var nativeX = this.imagingHelper.logicalToPhysicalX(x); + var nativeY = this.imagingHelper.logicalToPhysicalY(y); + var nativeNumbers = JSON.encode({nativeW: nativeW, nativeH: nativeH, nativeX: nativeX, nativeY: nativeY}); + return nativeNumbers } - var last_poly_split = String.split(poly_first_split[k], ',') + else if (annot.type == 'polyline' || annot.type == 'pencil' || annot.type == 'line') { + var x = annot.x; + var y = annot.y; + var w = annot.w; + var h = annot.h; + var point = annot.points; - var lastPolyPoint = new OpenSeadragon.Point(parseFloat(last_poly_split[0]), parseFloat(last_poly_split[1])) + var nativeW = this.imagingHelper.logicalToPhysicalDistance(w); + var nativeH = this.imagingHelper.logicalToPhysicalDistance(h); + var nativeX = this.imagingHelper.logicalToPhysicalX(x); + var nativeY = this.imagingHelper.logicalToPhysicalY(y); - points += this.imagingHelper.logicalToPhysicalX(lastPolyPoint.x) + ',' + this.imagingHelper.logicalToPhysicalY(lastPolyPoint.y) + var poly_first_split = String.split(point, ' '); + var points = ''; + for (var k = 0; k < poly_first_split.length - 1; k++) { + var poly_second_split = String.split(poly_first_split[k], ','); - var nativeNumbers = JSON.encode({nativeW: nativeW,nativeH: nativeH,nativeX: nativeX,nativeY: nativeY,nativePoints: points}) - return nativeNumbers - } + var polyPoint = new OpenSeadragon.Point(parseFloat(poly_second_split[0]), parseFloat(poly_second_split[1])); - else - return JSON.encode(annot) -} + points += this.imagingHelper.logicalToPhysicalX(polyPoint.x) + ',' + this.imagingHelper.logicalToPhysicalY(polyPoint.y) + ' ' + } + + var last_poly_split = String.split(poly_first_split[k], ','); + + var lastPolyPoint = new OpenSeadragon.Point(parseFloat(last_poly_split[0]), parseFloat(last_poly_split[1])); + + points += this.imagingHelper.logicalToPhysicalX(lastPolyPoint.x) + ',' + this.imagingHelper.logicalToPhysicalY(lastPolyPoint.y); + + var nativeNumbers = JSON.encode({ + nativeW: nativeW, + nativeH: nativeH, + nativeX: nativeX, + nativeY: nativeY, + nativePoints: points + }); + return nativeNumbers + } + + else + return JSON.encode(annot) +}; annotools.prototype.convertFromNative = function (annot, end) { - if (annot.type == 'rect' || annot.type == 'ellipse') { - var x = annot.x - var y = annot.y - var w = annot.w - var h = annot.h - var x_end = end.x - var y_end = end.y - - var nativeX_end = this.imagingHelper.physicalToLogicalX(x_end) - var nativeY_end = this.imagingHelper.physicalToLogicalY(y_end) - var nativeX = this.imagingHelper.physicalToLogicalX(x) - var nativeY = this.imagingHelper.physicalToLogicalY(y) - var nativeW = nativeX_end - nativeX - var nativeH = nativeY_end - nativeY - - var globalNumber = JSON.encode({nativeW: nativeW, nativeH: nativeH, nativeX: nativeX, nativeY: nativeY}) - - return globalNumber - } - - else if (annot.type == 'polyline' || annot.type == 'pencil' || annot.type == 'line') { - var x = annot.x - var y = annot.y - var w = annot.w - var h = annot.h - var point = annot.points - var poly_first_split = String.split(point, ' ') - var points = '' - for (var k = 0; k < poly_first_split.length - 1; k++) { - var poly_second_split = String.split(poly_first_split[k], ',') - - var polyPoint = new OpenSeadragon.Point(parseFloat(poly_second_split[0]), parseFloat(poly_second_split[1])) - - points += this.imagingHelper.physicalToLogicalX(polyPoint.x) + ',' + this.imagingHelper.physicalToLogicalY(polyPoint.y) + ' ' + if (annot.type == 'rect' || annot.type == 'ellipse') { + var x = annot.x; + var y = annot.y; + var w = annot.w; + var h = annot.h; + var x_end = end.x; + var y_end = end.y; + + var nativeX_end = this.imagingHelper.physicalToLogicalX(x_end); + var nativeY_end = this.imagingHelper.physicalToLogicalY(y_end); + var nativeX = this.imagingHelper.physicalToLogicalX(x); + var nativeY = this.imagingHelper.physicalToLogicalY(y); + var nativeW = nativeX_end - nativeX; + var nativeH = nativeY_end - nativeY; + + var globalNumber = JSON.encode({nativeW: nativeW, nativeH: nativeH, nativeX: nativeX, nativeY: nativeY}); + + return globalNumber } - var last_poly_split = String.split(poly_first_split[k], ',') + else if (annot.type == 'polyline' || annot.type == 'pencil' || annot.type == 'line') { + var x = annot.x; + var y = annot.y; + var w = annot.w; + var h = annot.h; + var point = annot.points; + var poly_first_split = String.split(point, ' '); + var points = ''; + for (var k = 0; k < poly_first_split.length - 1; k++) { + var poly_second_split = String.split(poly_first_split[k], ','); - var lastPolyPoint = new OpenSeadragon.Point(parseFloat(last_poly_split[0]), parseFloat(last_poly_split[1])) + var polyPoint = new OpenSeadragon.Point(parseFloat(poly_second_split[0]), parseFloat(poly_second_split[1])); - points += this.imagingHelper.physicalToLogicalX(lastPolyPoint.x) + ',' + this.imagingHelper.physicalToLogicalY(lastPolyPoint.y) - var x_end = end.x - var y_end = end.y + points += this.imagingHelper.physicalToLogicalX(polyPoint.x) + ',' + this.imagingHelper.physicalToLogicalY(polyPoint.y) + ' ' + } - var nativeX_end = this.imagingHelper.physicalToLogicalX(x_end) - var nativeY_end = this.imagingHelper.physicalToLogicalY(y_end) - var nativeX = this.imagingHelper.physicalToLogicalX(x) - var nativeY = this.imagingHelper.physicalToLogicalY(y) - var nativeW = nativeX_end - nativeX - var nativeH = nativeY_end - nativeY - var nativePoints = points + var last_poly_split = String.split(poly_first_split[k], ','); - var globalNumber = JSON.encode({nativeW: nativeW, nativeH: nativeH, nativeX: nativeX, nativeY: nativeY,points: nativePoints}) + var lastPolyPoint = new OpenSeadragon.Point(parseFloat(last_poly_split[0]), parseFloat(last_poly_split[1])); - return globalNumber - } + points += this.imagingHelper.physicalToLogicalX(lastPolyPoint.x) + ',' + this.imagingHelper.physicalToLogicalY(lastPolyPoint.y); + var x_end = end.x; + var y_end = end.y; - else - return JSON.encode(annot) -} + var nativeX_end = this.imagingHelper.physicalToLogicalX(x_end); + var nativeY_end = this.imagingHelper.physicalToLogicalY(y_end); + var nativeX = this.imagingHelper.physicalToLogicalX(x); + var nativeY = this.imagingHelper.physicalToLogicalY(y); + var nativeW = nativeX_end - nativeX; + var nativeH = nativeY_end - nativeY; + var nativePoints = points; + + var globalNumber = JSON.encode({ + nativeW: nativeW, + nativeH: nativeH, + nativeX: nativeX, + nativeY: nativeY, + points: nativePoints + }); + + return globalNumber + } + + else + return JSON.encode(annot) +}; annotools.prototype.convertAllToNative = function () { - for (index = 0; index < this.annotations.length; index++) { - // unparsed = this.convertToNative(this.annotations[index]) - newannot = JSON.parse(this.convertToNative(this.annotations[index])) - this.annotations[index].x = newannot.nativeX - this.annotations[index].y = newannot.nativeY - this.annotations[index].w = newannot.nativeW - this.annotations[index].h = newannot.nativeH - } -} + for (index = 0; index < this.annotations.length; index++) { + // unparsed = this.convertToNative(this.annotations[index]) + newannot = JSON.parse(this.convertToNative(this.annotations[index])); + this.annotations[index].x = newannot.nativeX; + this.annotations[index].y = newannot.nativeY; + this.annotations[index].w = newannot.nativeW; + this.annotations[index].h = newannot.nativeH + } +}; + +annotools.prototype.drawEllipse = function (ctx) { + console.log('ellipsing!'); + this.removeMouseEvents(); + var started = false; + var min_x, min_y, max_x, max_y, w, h; + var startPosition; + this.drawCanvas.bind('mousedown', function (e) { + started = true; + startPosition = OpenSeadragon.getMousePosition(e.event); + x = startPosition.x; + y = startPosition.y + }); + + this.drawCanvas.bind('mousemove', function (e) { + if (started) { + ctx.clearRect(0, 0, this.drawCanvas.width, this.drawCanvas.height); + var currentMousePosition = OpenSeadragon.getMousePosition(e.event); + + min_x = Math.min(currentMousePosition.x, startPosition.x); + min_y = Math.min(currentMousePosition.y, startPosition.y); + max_x = Math.max(currentMousePosition.x, startPosition.x); + max_y = Math.max(currentMousePosition.y, startPosition.y); + w = Math.abs(max_x - min_x); + h = Math.abs(max_y - min_y); + + var kappa = .5522848; + var ox = (w / 2) * kappa; + var oy = (h / 2) * kappa; + var xe = min_x + w; + var ye = min_y + h; + var xm = min_x + w / 2; + var ym = min_y + h / 2; + + ctx.beginPath(); + ctx.moveTo(min_x, ym); + ctx.bezierCurveTo(min_x, ym - oy, xm - ox, min_y, xm, min_y); + ctx.bezierCurveTo(xm + ox, min_y, xe, ym - oy, xe, ym); + ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + ctx.bezierCurveTo(xm - ox, ye, min_x, ym + oy, min_x, ym); + ctx.closePath(); + ctx.strokeStyle = this.color; + ctx.stroke() + } + }.bind(this)); + + this.drawCanvas.bind('mouseup', function (e) { + started = false; + var finalMousePosition = new OpenSeadragon.getMousePosition(e.event); + min_x = Math.min(finalMousePosition.x, startPosition.x); + min_y = Math.min(finalMousePosition.y, startPosition.y); + max_x = Math.max(finalMousePosition.x, startPosition.x); + max_y = Math.max(finalMousePosition.y, startPosition.y); -annotools.prototype.drawEllipse = function (ctx) { - console.log('ellipsing!') - this.removeMouseEvents() - var started = false - var min_x,min_y,max_x,max_y,w,h - var startPosition - this.drawCanvas.bind('mousedown', function (e) { - started = true - startPosition = OpenSeadragon.getMousePosition(e.event) - x = startPosition.x - y = startPosition.y - }) - - this.drawCanvas.bind('mousemove', function (e) { - if (started) { - ctx.clearRect(0, 0, this.drawCanvas.width, this.drawCanvas.height) - var currentMousePosition = OpenSeadragon.getMousePosition(e.event) - - min_x = Math.min(currentMousePosition.x, startPosition.x) - min_y = Math.min(currentMousePosition.y, startPosition.y) - max_x = Math.max(currentMousePosition.x, startPosition.x) - max_y = Math.max(currentMousePosition.y, startPosition.y) - w = Math.abs(max_x - min_x) - h = Math.abs(max_y - min_y) - - var kappa = .5522848 - var ox = (w / 2) * kappa - var oy = (h / 2) * kappa - var xe = min_x + w - var ye = min_y + h - var xm = min_x + w / 2 - var ym = min_y + h / 2 - - ctx.beginPath() - ctx.moveTo(min_x, ym) - ctx.bezierCurveTo(min_x, ym - oy, xm - ox, min_y, xm, min_y) - ctx.bezierCurveTo(xm + ox, min_y, xe, ym - oy, xe, ym) - ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye) - ctx.bezierCurveTo(xm - ox, ye, min_x, ym + oy, min_x, ym) - ctx.closePath() - ctx.strokeStyle = this.color - ctx.stroke() - } - }.bind(this)) - - this.drawCanvas.bind('mouseup', function (e) { - started = false - var finalMousePosition = new OpenSeadragon.getMousePosition(e.event) - min_x = Math.min(finalMousePosition.x, startPosition.x) - min_y = Math.min(finalMousePosition.y, startPosition.y) - max_x = Math.max(finalMousePosition.x, startPosition.x) - max_y = Math.max(finalMousePosition.y, startPosition.y) - - var startRelativeMousePosition = new OpenSeadragon.Point(min_x, min_y).minus(OpenSeadragon.getElementOffset(viewer.canvas)) - var endRelativeMousePosition = new OpenSeadragon.Point(max_x, max_y).minus(OpenSeadragon.getElementOffset(viewer.canvas)) - var newAnnot = { - x: startRelativeMousePosition.x, - y: startRelativeMousePosition.y, - w: w, - h: h, - type: 'ellipse', - color: this.color, - loc: [] - } + var startRelativeMousePosition = new OpenSeadragon.Point(min_x, min_y).minus(OpenSeadragon.getElementOffset(viewer.canvas)); + var endRelativeMousePosition = new OpenSeadragon.Point(max_x, max_y).minus(OpenSeadragon.getElementOffset(viewer.canvas)); + var newAnnot = { + x: startRelativeMousePosition.x, + y: startRelativeMousePosition.y, + w: w, + h: h, + type: 'ellipse', + color: this.color, + loc: [] + }; - var globalNumbers = JSON.parse(this.convertFromNative(newAnnot, endRelativeMousePosition)) - - newAnnot.x = globalNumbers.nativeX - newAnnot.y = globalNumbers.nativeY - newAnnot.w = globalNumbers.nativeW - newAnnot.h = globalNumbers.nativeH - var loc = [] - loc[0] = parseFloat(newAnnot.x) - loc[1] = parseFloat(newAnnot.y) - newAnnot.loc = loc - this.promptForAnnotation(newAnnot, 'new', this, ctx) - }.bind(this)) -} + var globalNumbers = JSON.parse(this.convertFromNative(newAnnot, endRelativeMousePosition)); + + newAnnot.x = globalNumbers.nativeX; + newAnnot.y = globalNumbers.nativeY; + newAnnot.w = globalNumbers.nativeW; + newAnnot.h = globalNumbers.nativeH; + var loc = []; + loc[0] = parseFloat(newAnnot.x); + loc[1] = parseFloat(newAnnot.y); + newAnnot.loc = loc; + this.promptForAnnotation(newAnnot, 'new', this, ctx) + }.bind(this)) +}; annotools.prototype.drawRectangle = function (ctx) { console.log('drawing rectangle'); @@ -1241,47 +1274,47 @@ annotools.prototype.drawRectangle = function (ctx) { /* Highlight drawRectangle button and change cursor */ - this.removeMouseEvents() - var started = false - var min_x, min_y, max_x, max_y, w, h - var startPosition + this.removeMouseEvents(); + var started = false; + var min_x, min_y, max_x, max_y, w, h; + var startPosition; this.drawCanvas.addEvent('mousedown', function (e) { - started = true - startPosition = OpenSeadragon.getMousePosition(e.event) - x = startPosition.x + started = true; + startPosition = OpenSeadragon.getMousePosition(e.event); + x = startPosition.x; y = startPosition.y - }) + }); this.drawCanvas.addEvent('mousemove', function (e) { if (started) { - ctx.clearRect(0, 0, this.drawCanvas.width, this.drawCanvas.height) - var currentMousePosition = OpenSeadragon.getMousePosition(e.event) - - min_x = Math.min(currentMousePosition.x, startPosition.x) - min_y = Math.min(currentMousePosition.y, startPosition.y) - max_x = Math.max(currentMousePosition.x, startPosition.x) - max_y = Math.max(currentMousePosition.y, startPosition.y) - w = Math.abs(max_x - min_x) - h = Math.abs(max_y - min_y) + ctx.clearRect(0, 0, this.drawCanvas.width, this.drawCanvas.height); + var currentMousePosition = OpenSeadragon.getMousePosition(e.event); + + min_x = Math.min(currentMousePosition.x, startPosition.x); + min_y = Math.min(currentMousePosition.y, startPosition.y); + max_x = Math.max(currentMousePosition.x, startPosition.x); + max_y = Math.max(currentMousePosition.y, startPosition.y); + w = Math.abs(max_x - min_x); + h = Math.abs(max_y - min_y); //ctx.strokeStyle = this.color - ctx.strokeStyle = selectedAlgorithmColor - ctx.fillStyle = 'rgba(255, 255, 255, 0.2)' - ctx.fillRect(min_x, min_y, w, h) + ctx.strokeStyle = selectedAlgorithmColor; + ctx.fillStyle = 'rgba(255, 255, 255, 0.2)'; + ctx.fillRect(min_x, min_y, w, h); ctx.strokeRect(min_x, min_y, w, h) } - }.bind(this)) + }.bind(this)); this.drawCanvas.addEvent('mouseup', function (e) { - started = false - var finalMousePosition = new OpenSeadragon.getMousePosition(e.event) + started = false; + var finalMousePosition = new OpenSeadragon.getMousePosition(e.event); - min_x = Math.min(finalMousePosition.x, startPosition.x) - min_y = Math.min(finalMousePosition.y, startPosition.y) - max_x = Math.max(finalMousePosition.x, startPosition.x) - max_y = Math.max(finalMousePosition.y, startPosition.y) + min_x = Math.min(finalMousePosition.x, startPosition.x); + min_y = Math.min(finalMousePosition.y, startPosition.y); + max_x = Math.max(finalMousePosition.x, startPosition.x); + max_y = Math.max(finalMousePosition.y, startPosition.y); - var startRelativeMousePosition = new OpenSeadragon.Point(min_x, min_y).minus(OpenSeadragon.getElementOffset(viewer.canvas)) - var endRelativeMousePosition = new OpenSeadragon.Point(max_x, max_y).minus(OpenSeadragon.getElementOffset(viewer.canvas)) + var startRelativeMousePosition = new OpenSeadragon.Point(min_x, min_y).minus(OpenSeadragon.getElementOffset(viewer.canvas)); + var endRelativeMousePosition = new OpenSeadragon.Point(max_x, max_y).minus(OpenSeadragon.getElementOffset(viewer.canvas)); var newAnnot = { x: startRelativeMousePosition.x, y: startRelativeMousePosition.y, @@ -1291,22 +1324,22 @@ annotools.prototype.drawRectangle = function (ctx) { //color: this.color, color: selectedAlgorithmColor, loc: [] - } + }; - var globalNumbers = JSON.parse(this.convertFromNative(newAnnot, endRelativeMousePosition)) + var globalNumbers = JSON.parse(this.convertFromNative(newAnnot, endRelativeMousePosition)); - newAnnot.x = globalNumbers.nativeX - newAnnot.y = globalNumbers.nativeY - newAnnot.w = globalNumbers.nativeW - newAnnot.h = globalNumbers.nativeH - var loc = [] - loc[0] = parseFloat(newAnnot.x) - loc[1] = parseFloat(newAnnot.y) + newAnnot.x = globalNumbers.nativeX; + newAnnot.y = globalNumbers.nativeY; + newAnnot.w = globalNumbers.nativeW; + newAnnot.h = globalNumbers.nativeH; + var loc = []; + loc[0] = parseFloat(newAnnot.x); + loc[1] = parseFloat(newAnnot.y); newAnnot.loc = loc; console.log("newAnnot object inside of drawRectangle func:"); console.log(newAnnot); // convert to geojson - var geoNewAnnot = this.convertRectToGeo(newAnnot) + var geoNewAnnot = this.convertRectToGeo(newAnnot); console.log("geoNewAnnot object inside of drawRectangle func:"); console.log(geoNewAnnot); // geoNewAnnot = newAnnot @@ -1319,10 +1352,10 @@ annotools.prototype.drawRectangle = function (ctx) { }; annotools.prototype.drawPencil = function (ctx) { - this.removeMouseEvents() - var started = false - var pencil = [] - var newpoly = [] + this.removeMouseEvents(); + var started = false; + var pencil = []; + var newpoly = []; /* Change button and cursor */ jQuery("canvas").css("cursor", "crosshair"); @@ -1343,62 +1376,62 @@ annotools.prototype.drawPencil = function (ctx) { } this.drawCanvas.addEvent('mousedown', function (e) { - started = true - var startPoint = OpenSeadragon.getMousePosition(e.event) - var relativeStartPoint = startPoint.minus(OpenSeadragon.getElementOffset(viewer.canvas)) + started = true; + var startPoint = OpenSeadragon.getMousePosition(e.event); + var relativeStartPoint = startPoint.minus(OpenSeadragon.getElementOffset(viewer.canvas)); newpoly.push({ 'x': relativeStartPoint.x, 'y': relativeStartPoint.y - }) - ctx.beginPath() - ctx.moveTo(relativeStartPoint.x, relativeStartPoint.y) + }); + ctx.beginPath(); + ctx.moveTo(relativeStartPoint.x, relativeStartPoint.y); //ctx.strokeStyle = this.color ctx.strokeStyle = selectedAlgorithmColor; ctx.stroke() - }.bind(this)) + }.bind(this)); this.drawCanvas.addEvent('mousemove', function (e) { - var newPoint = OpenSeadragon.getMousePosition(e.event) - var newRelativePoint = newPoint.minus(OpenSeadragon.getElementOffset(viewer.canvas)) + var newPoint = OpenSeadragon.getMousePosition(e.event); + var newRelativePoint = newPoint.minus(OpenSeadragon.getElementOffset(viewer.canvas)); if (started) { newpoly.push({ 'x': newRelativePoint.x, 'y': newRelativePoint.y - }) + }); - ctx.lineTo(newRelativePoint.x, newRelativePoint.y) + ctx.lineTo(newRelativePoint.x, newRelativePoint.y); ctx.stroke() } - }) + }); this.drawCanvas.addEvent('mouseup', function (e) { - started = false - pencil.push(newpoly) - newpoly = [] - numpoint = 0 - var x, y, w, h - x = pencil[0][0].x - y = pencil[0][0].y - - var maxdistance = 0 - var points = '' - var endRelativeMousePosition + started = false; + pencil.push(newpoly); + newpoly = []; + numpoint = 0; + var x, y, w, h; + x = pencil[0][0].x; + y = pencil[0][0].y; + + var maxdistance = 0; + var points = ''; + var endRelativeMousePosition; for (var i = 0; i < pencil.length; i++) { - newpoly = pencil[i] + newpoly = pencil[i]; for (j = 0; j < newpoly.length - 1; j++) { - points += newpoly[j].x + ',' + newpoly[j].y + ' ' + points += newpoly[j].x + ',' + newpoly[j].y + ' '; if (((newpoly[j].x - x) * (newpoly[j].x - x) + (newpoly[j].y - y) * (newpoly[j].y - y)) > maxdistance) { - maxdistance = ((newpoly[j].x - x) * (newpoly[j].x - x) + (newpoly[j].y - y) * (newpoly[j].y - y)) - var endMousePosition = new OpenSeadragon.Point(newpoly[j].x, newpoly[j].y) + maxdistance = ((newpoly[j].x - x) * (newpoly[j].x - x) + (newpoly[j].y - y) * (newpoly[j].y - y)); + var endMousePosition = new OpenSeadragon.Point(newpoly[j].x, newpoly[j].y); endRelativeMousePosition = endMousePosition.minus(OpenSeadragon.getElementOffset(viewer.canvas)) } } - points = points.slice(0, -1) + points = points.slice(0, -1); points += ';' } - points = points.slice(0, -1) + points = points.slice(0, -1); var newAnnot = { x: x, @@ -1410,21 +1443,21 @@ annotools.prototype.drawPencil = function (ctx) { //color: this.color, color: selectedAlgorithmColor, loc: [] - } - - var globalNumbers = JSON.parse(this.convertFromNative(newAnnot, endRelativeMousePosition)) - newAnnot.x = globalNumbers.nativeX - newAnnot.y = globalNumbers.nativeY - newAnnot.w = globalNumbers.nativeW - newAnnot.h = globalNumbers.nativeH - newAnnot.points = globalNumbers.points - var loc = [] - loc[0] = parseFloat(newAnnot.x) - loc[1] = parseFloat(newAnnot.y) - newAnnot.loc = loc - console.log(newAnnot) - var geojsonAnnot = this.convertPencilToGeo(newAnnot) - this.promptForAnnotation(geojsonAnnot, 'new', this, ctx) + }; + + var globalNumbers = JSON.parse(this.convertFromNative(newAnnot, endRelativeMousePosition)); + newAnnot.x = globalNumbers.nativeX; + newAnnot.y = globalNumbers.nativeY; + newAnnot.w = globalNumbers.nativeW; + newAnnot.h = globalNumbers.nativeH; + newAnnot.points = globalNumbers.points; + var loc = []; + loc[0] = parseFloat(newAnnot.x); + loc[1] = parseFloat(newAnnot.y); + newAnnot.loc = loc; + console.log(newAnnot); + var geojsonAnnot = this.convertPencilToGeo(newAnnot); + this.promptForAnnotation(geojsonAnnot, 'new', this, ctx); /* Change button back to inactive*/ jQuery("canvas").css("cursor", "default"); @@ -1435,552 +1468,553 @@ annotools.prototype.drawPencil = function (ctx) { }; annotools.prototype.drawMeasure = function (ctx) { - this.removeMouseEvents() - var started = false - var x0,y0,x1,y1 - var length - - this.drawCanvas.addEvent('mousedown', function (e) { - if (!started) { - var startPosition = OpenSeadragon.getMousePosition(e.event) - var startRelativeMousePosition = startPosition.minus(OpenSeadragon.getElementOffset(viewer.canvas)) - x0 = startRelativeMousePosition.x - y0 = startRelativeMousePosition.y - started = true - }else { - var endPosition = OpenSeadragon.getMousePosition(e.event) - var endRelativePosition = endPosition.minus(OpenSeadragon.getElementOffset(viewer.canvas)) - x1 = endRelativePosition.x - y1 = endRelativePosition.y - ctx.beginPath() - ctx.moveTo(x0, y0) - ctx.lineTo(x1, y1) - ctx.strokeStyle = this.color - ctx.stroke() - ctx.closePath() - - var minX, minY = 0 - var maxX, maxY = 0 - if (x1 > x0) { - minX = x0 - maxX = x1 - }else { - minX = x1 - maxX = x0 - } - if (y1 > y0) { - minY = y0 - maxY = y1 - }else { - minY = y1 - maxY = y0 - } - - var x_dist = ((this.imagingHelper.physicalToDataX(x0)) - (this.imagingHelper.physicalToDataX(x1))) - var y_dist = ((this.imagingHelper.physicalToDataY(y0)) - (this.imagingHelper.physicalToDataY(y1))) - - var x_micron = this.mppx * x_dist - var y_micron = this.mppy * y_dist - - var length = Math.sqrt(x_micron.pow(2) + y_micron.pow(2)) - points = (x1 + ',' + y1) - var w = 0 - var h = 0 - var newAnnot = - { - x: x0, - y: y0, - w: w, - h: h, - type: 'line', - points: points, - color: this.color, - loc: [], - length: length - } - var finalPosition = new OpenSeadragon.Point(maxX, maxY) - var finalRelativePosition = finalPosition.minus(OpenSeadragon.getElementOffset()) - - var globalNumbers = JSON.parse(this.convertFromNative(newAnnot, finalRelativePosition)) - newAnnot.x = globalNumbers.nativeX - newAnnot.y = globalNumbers.nativeY - newAnnot.w = globalNumbers.nativeW - newAnnot.h = globalNumbers.nativeH - newAnnot.points = globalNumbers.points - var loc = [] - loc[0] = parseFloat(newAnnot.x) - loc[1] = parseFloat(newAnnot.y) - newAnnot.loc = loc - this.promptForAnnotation(newAnnot, 'new', this, ctx) - started = false - } - }.bind(this)) - - this.drawCanvas.addEvent('mousemove', function (e) { - if (started) { - ctx.clearRect(0, 0, this.drawCanvas.width, this.drawCanvas.height) - var currentPosition = OpenSeadragon.getMousePosition(e.event) - var currentRelativePosition = OpenSeadragon.getMousePosition(e.event) - - x1 = currentRelativePosition.x - y1 = currentRelativePosition.y - - ctx.beginPath() - ctx.moveTo(x0, y0) - ctx.lineTo(x1, y1) - ctx.strokeStyle = this.color - ctx.stroke() - ctx.closePath() - } - }.bind(this)) -} + this.removeMouseEvents(); + var started = false; + var x0, y0, x1, y1; + var length; -annotools.prototype.drawPolyline = function (ctx) { - this.removeMouseEvents() - var started = true - var newpoly = [] - var numpoint = 0 - this.drawCanvas.addEvent('mousedown', function (e) { - if (started) { - var newPoint = OpenSeadragon.getMousePosition(e.event) - var newRelativePoint = newPoint.minus(OpenSeadragon.getElementOffset(viewer.canvas)) - ctx.fillStyle = this.color - ctx.beginPath() - ctx.arc(e.event.layerX, e.event.layerY, 2, 0, Math.PI * 2, true) - ctx.closePath() - ctx.fill - newpoly.push({'x': newRelativePoint.x, - 'y': newRelativePoint.y}) - - if (numpoint > 0) { - ctx.beginPath() - ctx.moveTo(newpoly[numpoint].x, newpoly[numpoint].y) - ctx.lineTo(newpoly[numpoint - 1].x, newpoly[numpoint - 1].y) - ctx.strokeStyle = this.color - ctx.stroke() - } + this.drawCanvas.addEvent('mousedown', function (e) { + if (!started) { + var startPosition = OpenSeadragon.getMousePosition(e.event); + var startRelativeMousePosition = startPosition.minus(OpenSeadragon.getElementOffset(viewer.canvas)); + x0 = startRelativeMousePosition.x; + y0 = startRelativeMousePosition.y; + started = true + } else { + var endPosition = OpenSeadragon.getMousePosition(e.event); + var endRelativePosition = endPosition.minus(OpenSeadragon.getElementOffset(viewer.canvas)); + x1 = endRelativePosition.x; + y1 = endRelativePosition.y; + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.strokeStyle = this.color; + ctx.stroke(); + ctx.closePath(); + + var minX, minY = 0; + var maxX, maxY = 0; + if (x1 > x0) { + minX = x0; + maxX = x1 + } else { + minX = x1; + maxX = x0 + } + if (y1 > y0) { + minY = y0; + maxY = y1 + } else { + minY = y1; + maxY = y0 + } - numpoint++ - } - }.bind(this)) + var x_dist = ((this.imagingHelper.physicalToDataX(x0)) - (this.imagingHelper.physicalToDataX(x1))); + var y_dist = ((this.imagingHelper.physicalToDataY(y0)) - (this.imagingHelper.physicalToDataY(y1))); + + var x_micron = this.mppx * x_dist; + var y_micron = this.mppy * y_dist; + + var length = Math.sqrt(x_micron.pow(2) + y_micron.pow(2)); + points = (x1 + ',' + y1); + var w = 0; + var h = 0; + var newAnnot = + { + x: x0, + y: y0, + w: w, + h: h, + type: 'line', + points: points, + color: this.color, + loc: [], + length: length + }; + var finalPosition = new OpenSeadragon.Point(maxX, maxY); + var finalRelativePosition = finalPosition.minus(OpenSeadragon.getElementOffset()); + + var globalNumbers = JSON.parse(this.convertFromNative(newAnnot, finalRelativePosition)); + newAnnot.x = globalNumbers.nativeX; + newAnnot.y = globalNumbers.nativeY; + newAnnot.w = globalNumbers.nativeW; + newAnnot.h = globalNumbers.nativeH; + newAnnot.points = globalNumbers.points; + var loc = []; + loc[0] = parseFloat(newAnnot.x); + loc[1] = parseFloat(newAnnot.y); + newAnnot.loc = loc; + this.promptForAnnotation(newAnnot, 'new', this, ctx); + started = false + } + }.bind(this)); + + this.drawCanvas.addEvent('mousemove', function (e) { + if (started) { + ctx.clearRect(0, 0, this.drawCanvas.width, this.drawCanvas.height); + var currentPosition = OpenSeadragon.getMousePosition(e.event); + var currentRelativePosition = OpenSeadragon.getMousePosition(e.event); + + x1 = currentRelativePosition.x; + y1 = currentRelativePosition.y; + + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.strokeStyle = this.color; + ctx.stroke(); + ctx.closePath() + } + }.bind(this)) +}; - this.drawCanvas.addEvent('dblclick', function (e) { - started = false - ctx.beginPath() - ctx.moveTo(newpoly[numpoint - 1].x, newpoly[numpoint - 1].y) - ctx.lineTo(newpoly[0].x, newpoly[0].y) - ctx.stroke() - var x,y,w,h +annotools.prototype.drawPolyline = function (ctx) { + this.removeMouseEvents(); + var started = true; + var newpoly = []; + var numpoint = 0; + this.drawCanvas.addEvent('mousedown', function (e) { + if (started) { + var newPoint = OpenSeadragon.getMousePosition(e.event); + var newRelativePoint = newPoint.minus(OpenSeadragon.getElementOffset(viewer.canvas)); + ctx.fillStyle = this.color; + ctx.beginPath(); + ctx.arc(e.event.layerX, e.event.layerY, 2, 0, Math.PI * 2, true); + ctx.closePath(); + ctx.fill; + newpoly.push({ + 'x': newRelativePoint.x, + 'y': newRelativePoint.y + }); + + if (numpoint > 0) { + ctx.beginPath(); + ctx.moveTo(newpoly[numpoint].x, newpoly[numpoint].y); + ctx.lineTo(newpoly[numpoint - 1].x, newpoly[numpoint - 1].y); + ctx.strokeStyle = this.color; + ctx.stroke() + } + + numpoint++ + } + }.bind(this)); - x = newpoly[0].x - y = newpoly[0].y + this.drawCanvas.addEvent('dblclick', function (e) { + started = false; + ctx.beginPath(); + ctx.moveTo(newpoly[numpoint - 1].x, newpoly[numpoint - 1].y); + ctx.lineTo(newpoly[0].x, newpoly[0].y); + ctx.stroke(); + var x, y, w, h; - var maxdistance = 0 + x = newpoly[0].x; + y = newpoly[0].y; - // var tip = prompt("Please Enter Some Description","") + var maxdistance = 0; - var points = '' + // var tip = prompt("Please Enter Some Description","") - var endMousePosition - for (var i = 0; i < numpoint - 1; i++) { - points += newpoly[i].x + ',' + newpoly[i].y + ' ' - if (((newpoly[i].x - x) * (newpoly[i].x - x) + (newpoly[i].y - y) * (newpoly[i].y - y)) > maxdistance) { - maxdistance = ((newpoly[i].x - x) * (newpoly[i].x - x) + (newpoly[i].y - y) * (newpoly[i].y - y)) + var points = ''; - endMousePosition = new OpenSeadragon.Point(newpoly[i].x, newpoly[i].y) - w = Math.abs(newpoly[i].x - x) - h = Math.abs(newpoly[i].y - y) - } - } + var endMousePosition; + for (var i = 0; i < numpoint - 1; i++) { + points += newpoly[i].x + ',' + newpoly[i].y + ' '; + if (((newpoly[i].x - x) * (newpoly[i].x - x) + (newpoly[i].y - y) * (newpoly[i].y - y)) > maxdistance) { + maxdistance = ((newpoly[i].x - x) * (newpoly[i].x - x) + (newpoly[i].y - y) * (newpoly[i].y - y)); - points += newpoly[i].x + ',' + newpoly[i].y + endMousePosition = new OpenSeadragon.Point(newpoly[i].x, newpoly[i].y); + w = Math.abs(newpoly[i].x - x); + h = Math.abs(newpoly[i].y - y) + } + } - var endRelativeMousePosition = endMousePosition.minus(OpenSeadragon.getElementOffset(viewer.canvas)) + points += newpoly[i].x + ',' + newpoly[i].y; - var newAnnot = { - x: x, - y: y, - w: w, - h: h, - type: 'polyline', - points: points, - color: this.color, - loc: [] - } + var endRelativeMousePosition = endMousePosition.minus(OpenSeadragon.getElementOffset(viewer.canvas)); - var globalNumbers = JSON.parse(this.convertFromNative(newAnnot, endRelativeMousePosition)) - - newAnnot.x = globalNumbers.nativeX - newAnnot.y = globalNumbers.nativeY - newAnnot.w = globalNumbers.nativeW - newAnnot.h = globalNumbers.nativeH - newAnnot.points = globalNumbers.points - var loc = [] - loc[0] = newAnnot.x - loc[1] = newAnnot.y - newAnnot.loc = loc - this.promptForAnnotation(newAnnot, 'new', this, ctx) - }.bind(this)) -} + var newAnnot = { + x: x, + y: y, + w: w, + h: h, + type: 'polyline', + points: points, + color: this.color, + loc: [] + }; + + var globalNumbers = JSON.parse(this.convertFromNative(newAnnot, endRelativeMousePosition)); + + newAnnot.x = globalNumbers.nativeX; + newAnnot.y = globalNumbers.nativeY; + newAnnot.w = globalNumbers.nativeW; + newAnnot.h = globalNumbers.nativeH; + newAnnot.points = globalNumbers.points; + var loc = []; + loc[0] = newAnnot.x; + loc[1] = newAnnot.y; + newAnnot.loc = loc; + this.promptForAnnotation(newAnnot, 'new', this, ctx) + }.bind(this)) +}; annotools.prototype.saveState = function () { - if (this.iid) { - var jsonRequest = new Request.JSON({ - // url: IP + 'api/state.php', - url: 'api/Data/state.php', - onSuccess: function (e) { - this.showMessage('saved to the server') - }.bind(this), - onFailure: function (e) { - this.showMessage('Error Saving the state,please check you saveState funciton') - }.bind(this) - }).post({ - 'iid': this.iid, - 'zoom': iip.view.res, - 'left': iip.view.x, - 'top': iip.view.y - }) - } else this.showMessage('Sorry, This Function is Only Supported With the Database Version') -} + if (this.iid) { + var jsonRequest = new Request.JSON({ + // url: IP + 'api/state.php', + url: 'api/Data/state.php', + onSuccess: function (e) { + this.showMessage('saved to the server') + }.bind(this), + onFailure: function (e) { + this.showMessage('Error Saving the state,please check you saveState funciton') + }.bind(this) + }).post({ + 'iid': this.iid, + 'zoom': iip.view.res, + 'left': iip.view.x, + 'top': iip.view.y + }) + } else this.showMessage('Sorry, This Function is Only Supported With the Database Version') +}; annotools.prototype.retrieveTemplate = function () { - var jsonReturn = '' - /* - * Ganesh - */ - - var jsonRequest = new Request.JSON({ - url: 'api/Data/retreiveTemplate.php', // Ameen, fix your spelling! - async: false, - onSuccess: function (e) { - jsonReturn = JSON.parse(e)[0] - console.log(jsonReturn) - }.bind(this), - onFailure: function (e) { - this.showMessage('Error retrieving AnnotationTemplate, please check your retrieveTemplate.php') - }.bind(this) - }).get() - - return jsonReturn -} + var jsonReturn = ''; + /* + * Ganesh + */ + + var jsonRequest = new Request.JSON({ + url: 'api/Data/retreiveTemplate.php', // Ameen, fix your spelling! + async: false, + onSuccess: function (e) { + jsonReturn = JSON.parse(e)[0]; + console.log(jsonReturn) + }.bind(this), + onFailure: function (e) { + this.showMessage('Error retrieving AnnotationTemplate, please check your retrieveTemplate.php') + }.bind(this) + }).get(); + + return jsonReturn +}; annotools.prototype.retrieveSingleAnnot = function (annotId) { - var jsonReturn - var jsonRequest = new Request.JSON({ - url: 'api/Data/retreiveSingleAnnot.php', // Ameen, fix your spelling! Again! - async: false, - onSuccess: function (e) { - jsonReturn = JSON.parse(e)[0] - }.bind(this), - onFailure: function (e) { - this.showMessage('Error retrieving Annotation, please check your trieveSingleAnnot.php') - }.bind(this) - }).get({'annotId': annotId}) - - return jsonReturn -} + var jsonReturn; + var jsonRequest = new Request.JSON({ + url: 'api/Data/retreiveSingleAnnot.php', // Ameen, fix your spelling! Again! + async: false, + onSuccess: function (e) { + jsonReturn = JSON.parse(e)[0] + }.bind(this), + onFailure: function (e) { + this.showMessage('Error retrieving Annotation, please check your trieveSingleAnnot.php') + }.bind(this) + }).get({'annotId': annotId}); + + return jsonReturn +}; annotools.prototype.populateForm = function (annotationTemplateJson, annotationTextJson, mode) { - var form = '' - for (var key in annotationTemplateJson) { - if (annotationTemplateJson.hasOwnProperty(key) && key != '_id') { - form += "

" + key + ':

' - var val = annotationTemplateJson[key] - if (val == 'text') { - form += "' - } - } else { - for (var i = 0; i < options.length; i++) { - form += "'; + var val = annotationTemplateJson[key]; + if (val == 'text') { + form += "' + } + } else { + for (var i = 0; i < options.length; i++) { + form += "' + } + } } - form += '>' + options[i] + '' - } } - } } - } - return form -} + return form +}; -function handleWorkOrder (annot) { - console.log(annot) +function handleWorkOrder(annot) { + console.log(annot) } - annotools.prototype.promptForWorkOrder = function (newAnnot, mode, annotools, ctx) { - console.log(newAnnot) - console.log(mode) - console.log(annotools) - console.log(ctx) - - var panel = jQuery('#panel').show() - var iid = this.iid - var x = annotools.imagingHelper.physicalToDataX(annotools.imagingHelper.logicalToPhysicalX(newAnnot.x)) - var y = annotools.imagingHelper.physicalToDataY(annotools.imagingHelper.logicalToPhysicalY(newAnnot.y)) - var w = (annotools.imagingHelper.physicalToDataX(annotools.imagingHelper.logicalToPhysicalX((newAnnot.x + newAnnot.w)))) - x - var h = (annotools.imagingHelper.physicalToDataY(annotools.imagingHelper.logicalToPhysicalY(newAnnot.y + newAnnot.h))) - y - x = parseInt(x) - y = parseInt(y) - w = parseInt(w) - h = parseInt(h) - if (w * h > 1000000) { - newAnnot.w = annotools.imagingHelper.dataToLogicalX(1000) - newAnnot.h = annotools.imagingHelper.dataToLogicalY(1000) - w = 1000 - h = 1000 + console.log(newAnnot); + console.log(mode); + console.log(annotools); + console.log(ctx); + + var panel = jQuery('#panel').show(); + var iid = this.iid; + var x = annotools.imagingHelper.physicalToDataX(annotools.imagingHelper.logicalToPhysicalX(newAnnot.x)); + var y = annotools.imagingHelper.physicalToDataY(annotools.imagingHelper.logicalToPhysicalY(newAnnot.y)); + var w = (annotools.imagingHelper.physicalToDataX(annotools.imagingHelper.logicalToPhysicalX((newAnnot.x + newAnnot.w)))) - x; + var h = (annotools.imagingHelper.physicalToDataY(annotools.imagingHelper.logicalToPhysicalY(newAnnot.y + newAnnot.h))) - y; + x = parseInt(x); + y = parseInt(y); + w = parseInt(w); + h = parseInt(h); + if (w * h > 1000000) { + newAnnot.w = annotools.imagingHelper.dataToLogicalX(1000); + newAnnot.h = annotools.imagingHelper.dataToLogicalY(1000); + w = 1000; + h = 1000; + panel.html(function () { + return "

Work Order(Error)

Error: Very large ROI.
" + 'Width: ' + w + '
' + 'Height: ' + h + "
Please try creating a smaller ROI. Zooming into the ROI would help.
We currently support 1000X1000 tiles
" + }); + jQuery('#cancelWorkOrder').click(function () { + console.log('here'); + jQuery('#panel').hide(); + annotools.drawLayer.hide(); + annotools.addMouseEvents() + }); + return + } panel.html(function () { - return "

Work Order(Error)

Error: Very large ROI.
" + 'Width: ' + w + '
' + 'Height: ' + h + "
Please try creating a smaller ROI. Zooming into the ROI would help.
We currently support 1000X1000 tiles
" - }) + return "

Work Order

  • x1: " + x + '
  • y1: ' + y + '
  • w: ' + w + '
  • h: ' + h + '
  • Algorithm: SuperSegmenter
  • ' + + "
  • Execution Id:
  • " + "
  • Notes: " + "

" + }); + + jQuery('#cancelWorkOrder').click(function () { - console.log('here') - jQuery('#panel').hide() - annotools.drawLayer.hide() - annotools.addMouseEvents() - }) - return - } - panel.html(function () { - return "

Work Order

  • x1: " + x + '
  • y1: ' + y + '
  • w: ' + w + '
  • h: ' + h + '
  • Algorithm: SuperSegmenter
  • ' - + "
  • Execution Id:
  • " + "
  • Notes: " + "

" - }) + console.log('here'); + jQuery('#panel').hide(); + annotools.drawLayer.hide(); + annotools.addMouseEvents() + }); - + jQuery('#submitWorkOrder').click(function () { + console.log('events...'); - jQuery('#cancelWorkOrder').click(function () { - console.log('here') - jQuery('#panel').hide() - annotools.drawLayer.hide() - annotools.addMouseEvents() - }) - - jQuery('#submitWorkOrder').click(function () { - console.log('events...') - - annotools.drawLayer.hide() - annotools.addMouseEvents() - - - var username = 'lastlegion' - var execution_id = jQuery('#order-execution_id').val() - var notes = jQuery('#order-notes').val() - var width = 48002 - var height = 35558 - if (iid == 'TCGA-06-0148-01Z-00-DX1') { - width = 26001 - height = 27968 - } - var order = { - 'type': 'order', - - 'data': { - 'title': username + ' :: ' + execution_id, - 'algorithm': 'SuperSegmenter', - 'execution_id': execution_id, - 'created_by': username, - 'notes': notes, - 'order': { - 'metadata': { - 'created_on': Date.now(), - 'created_by': 'lastlegion' - }, - 'image': { - 'width': width, - 'height': height, - 'case_id': iid - }, - 'roi': { - 'x': x, - 'y': y, - 'w': w, - 'h': h - }, - 'execution': { - 'execution_id': execution_id, - 'algorithm': 'SuperSegmenter', - 'parameters': [ - { - 'blur': 0.4 - }, - { - 'format': 'jpg' - } - ] - } + annotools.drawLayer.hide(); + annotools.addMouseEvents(); + + + var username = 'lastlegion'; + var execution_id = jQuery('#order-execution_id').val(); + var notes = jQuery('#order-notes').val(); + var width = 48002; + var height = 35558; + if (iid == 'TCGA-06-0148-01Z-00-DX1') { + width = 26001; + height = 27968 } - } - } + var order = { + 'type': 'order', + + 'data': { + 'title': username + ' :: ' + execution_id, + 'algorithm': 'SuperSegmenter', + 'execution_id': execution_id, + 'created_by': username, + 'notes': notes, + 'order': { + 'metadata': { + 'created_on': Date.now(), + 'created_by': 'lastlegion' + }, + 'image': { + 'width': width, + 'height': height, + 'case_id': iid + }, + 'roi': { + 'x': x, + 'y': y, + 'w': w, + 'h': h + }, + 'execution': { + 'execution_id': execution_id, + 'algorithm': 'SuperSegmenter', + 'parameters': [ + { + 'blur': 0.4 + }, + { + 'format': 'jpg' + } + ] + } + } + } + }; - - jQuery.post('api/Data/workOrder.php', order) - .done(function (res) { - console.log(res) - panel.html(function () { - annotools.addMouseEvents() - return 'Order Submitted!' - }) - panel.hide('slide') - }) - console.log('submit') - console.log(newAnnot) - console.log(order) - }.bind(newAnnot)) -} + + jQuery.post('api/Data/workOrder.php', order) + .done(function (res) { + console.log(res); + panel.html(function () { + annotools.addMouseEvents(); + return 'Order Submitted!' + }); + panel.hide('slide') + }); + console.log('submit'); + console.log(newAnnot); + console.log(order) + }.bind(newAnnot)) +}; annotools.prototype.promptForWorkOrder = function (newAnnot, mode, annotools, ctx) { - console.log(newAnnot) - console.log(mode) - console.log(annotools) - console.log(ctx) - - var panel = jQuery('#panel').show() - var iid = this.iid - var x = annotools.imagingHelper.physicalToDataX(annotools.imagingHelper.logicalToPhysicalX(newAnnot.x)) - var y = annotools.imagingHelper.physicalToDataY(annotools.imagingHelper.logicalToPhysicalY(newAnnot.y)) - var w = (annotools.imagingHelper.physicalToDataX(annotools.imagingHelper.logicalToPhysicalX((newAnnot.x + newAnnot.w)))) - x - var h = (annotools.imagingHelper.physicalToDataY(annotools.imagingHelper.logicalToPhysicalY(newAnnot.y + newAnnot.h))) - y - x = parseInt(x) - y = parseInt(y) - w = parseInt(w) - h = parseInt(h) - if (w * h > 1000000) { - newAnnot.w = annotools.imagingHelper.dataToLogicalX(1000) - newAnnot.h = annotools.imagingHelper.dataToLogicalY(1000) - w = 1000 - h = 1000 + console.log(newAnnot); + console.log(mode); + console.log(annotools); + console.log(ctx); + + var panel = jQuery('#panel').show(); + var iid = this.iid; + var x = annotools.imagingHelper.physicalToDataX(annotools.imagingHelper.logicalToPhysicalX(newAnnot.x)); + var y = annotools.imagingHelper.physicalToDataY(annotools.imagingHelper.logicalToPhysicalY(newAnnot.y)); + var w = (annotools.imagingHelper.physicalToDataX(annotools.imagingHelper.logicalToPhysicalX((newAnnot.x + newAnnot.w)))) - x; + var h = (annotools.imagingHelper.physicalToDataY(annotools.imagingHelper.logicalToPhysicalY(newAnnot.y + newAnnot.h))) - y; + x = parseInt(x); + y = parseInt(y); + w = parseInt(w); + h = parseInt(h); + if (w * h > 1000000) { + newAnnot.w = annotools.imagingHelper.dataToLogicalX(1000); + newAnnot.h = annotools.imagingHelper.dataToLogicalY(1000); + w = 1000; + h = 1000; + panel.html(function () { + return "

Work Order(Error)

Error: Very large ROI.
" + 'Width: ' + w + '
' + 'Height: ' + h + "
Please try creating a smaller ROI. Zooming into the ROI would help.
We currently support 1000X1000 tiles
" + }); + jQuery('#cancelWorkOrder').click(function () { + console.log('here'); + jQuery('#panel').hide(); + annotools.drawLayer.hide(); + annotools.addMouseEvents() + }); + return + } panel.html(function () { - return "

Work Order(Error)

Error: Very large ROI.
" + 'Width: ' + w + '
' + 'Height: ' + h + "
Please try creating a smaller ROI. Zooming into the ROI would help.
We currently support 1000X1000 tiles
" - }) + return "

Work Order

  • x1: " + x + '
  • y1: ' + y + '
  • w: ' + w + '
  • h: ' + h + '
  • Algorithm: SuperSegmenter
  • ' + + "
  • Execution Id:
  • " + "
  • Notes: " + "

" + }); + + jQuery('#cancelWorkOrder').click(function () { - console.log('here') - jQuery('#panel').hide() - annotools.drawLayer.hide() - annotools.addMouseEvents() - }) - return - } - panel.html(function () { - return "

Work Order

  • x1: " + x + '
  • y1: ' + y + '
  • w: ' + w + '
  • h: ' + h + '
  • Algorithm: SuperSegmenter
  • ' - + "
  • Execution Id:
  • " + "
  • Notes: " + "

" - }) - + console.log('here'); + jQuery('#panel').hide(); + annotools.drawLayer.hide(); + annotools.addMouseEvents() + }); - jQuery('#cancelWorkOrder').click(function () { - console.log('here') - jQuery('#panel').hide() - annotools.drawLayer.hide() - annotools.addMouseEvents() - }) - - jQuery('#submitWorkOrder').click(function () { - console.log('events...') - - // annotools.drawCanvas.removeEvents('mouseup') - // annotools.drawCanvas.removeEvents('mousedown') - // annotools.drawCanvas.removeEvents('mousemove') - annotools.drawLayer.hide() - annotools.addMouseEvents() - // annotools.removeMouseEvents() - // annotools.getMultiAnnot(); - - var username = 'lastlegion' - var execution_id = jQuery('#order-execution_id').val() - var notes = jQuery('#order-notes').val() - var width = 48002 - var height = 35558 - if (iid == 'TCGA-06-0148-01Z-00-DX1') { - width = 26001 - height = 27968 - } - var order = { - 'type': 'order', - - 'data': { - 'title': username + ' :: ' + execution_id, - 'algorithm': 'SuperSegmenter', - 'execution_id': execution_id, - 'created_by': username, - 'notes': notes, - 'order': { - 'metadata': { - 'created_on': Date.now(), - 'created_by': 'lastlegion' - }, - 'image': { - 'width': width, - 'height': height, - 'case_id': iid - }, - 'roi': { - 'x': x, - 'y': y, - 'w': w, - 'h': h - }, - 'execution': { - 'execution_id': execution_id, - 'algorithm': 'SuperSegmenter', - 'parameters': [ - { - 'blur': 0.4 - }, - { - 'format': 'jpg' - } - ] - } + jQuery('#submitWorkOrder').click(function () { + console.log('events...'); + + // annotools.drawCanvas.removeEvents('mouseup') + // annotools.drawCanvas.removeEvents('mousedown') + // annotools.drawCanvas.removeEvents('mousemove') + annotools.drawLayer.hide(); + annotools.addMouseEvents(); + // annotools.removeMouseEvents() + // annotools.getMultiAnnot(); + + var username = 'lastlegion'; + var execution_id = jQuery('#order-execution_id').val(); + var notes = jQuery('#order-notes').val(); + var width = 48002; + var height = 35558; + if (iid == 'TCGA-06-0148-01Z-00-DX1') { + width = 26001; + height = 27968 } - } - } + var order = { + 'type': 'order', + + 'data': { + 'title': username + ' :: ' + execution_id, + 'algorithm': 'SuperSegmenter', + 'execution_id': execution_id, + 'created_by': username, + 'notes': notes, + 'order': { + 'metadata': { + 'created_on': Date.now(), + 'created_by': 'lastlegion' + }, + 'image': { + 'width': width, + 'height': height, + 'case_id': iid + }, + 'roi': { + 'x': x, + 'y': y, + 'w': w, + 'h': h + }, + 'execution': { + 'execution_id': execution_id, + 'algorithm': 'SuperSegmenter', + 'parameters': [ + { + 'blur': 0.4 + }, + { + 'format': 'jpg' + } + ] + } + } + } + }; - - jQuery.post('api/Data/workOrder.php', order) - .done(function (res) { - console.log(res) - panel.html(function () { - annotools.addMouseEvents() - return 'Order Submitted!' - }) - panel.hide('slide') - }) - console.log('submit') - console.log(newAnnot) - console.log(order) - }.bind(newAnnot)) -} + + jQuery.post('api/Data/workOrder.php', order) + .done(function (res) { + console.log(res); + panel.html(function () { + annotools.addMouseEvents(); + return 'Order Submitted!' + }); + panel.hide('slide') + }); + console.log('submit'); + console.log(newAnnot); + console.log(order) + }.bind(newAnnot)) +}; annotools.prototype.promptForAnnotation = function (newAnnot, mode, annotools, ctx) { - jQuery('#panel').show('slide') - console.log(newAnnot); - jQuery('panel').html(''); - jQuery('#panel').html('' + - "

Enter a new annotation

" - + "
" - + "
" - + '
' + jQuery('#panel').show('slide'); + console.log(newAnnot); + jQuery('panel').html(''); + jQuery('#panel').html('' + + "

Enter a new annotation

" + + "
" + + "
" + + '
' + '
' ) - jQuery.get('api/Data/retrieveTemplateClone.php', function (data) { - console.log("after retrieveTemplate.php:"+data); - var schema = JSON.parse(data) - schema = JSON.parse(schema)[0] - console.log(schema) + jQuery.get('api/Data/retrieveTemplate.php?app_name=segment_curation', function (data) { + console.log("after retrieveTemplateByName.php:"+data); + var schema = JSON.parse(data); + schema = JSON.parse(schema)[0]; + //console.log(schema); + //schema.region.enum=["Good Segmentation","Clump"]; // console.log("retrieved template") var formSchema = { 'schema': schema, @@ -1990,341 +2024,340 @@ annotools.prototype.promptForAnnotation = function (newAnnot, mode, annotools, c 'type': 'submit', 'title': 'Submit' - }, - { - 'type': 'button', - 'title': 'Cancel', - 'onClick': function (e) { - console.log(e) - e.preventDefault() - // console.log("cancel") - cancelAnnotation() - } - } - ] - } - - formSchema.onSubmit = function (err, val) { - // Add form data to annotation - newAnnot.properties.annotations = val - console.log("inside formSchema.onSubmit of newAnnot object"); - console.log(newAnnot); - // Post annotation - annotools.addnewAnnot(newAnnot) - - // Hide Panel - jQuery('#panel').hide('slide') - annotools.drawLayer.hide() - annotools.addMouseEvents() - - return false - } - - var cancelAnnotation = function () { - console.log('cancel handler') - jQuery('#panel').hide('slide') - annotools.drawLayer.hide() - annotools.addMouseEvents() - } - - jQuery('#annotationsForm').jsonForm(formSchema) - }) -} + }, + { + 'type': 'button', + 'title': 'Cancel', + 'onClick': function (e) { + console.log(e); + e.preventDefault(); + // console.log("cancel") + cancelAnnotation() + } + } + ] + }; + + formSchema.onSubmit = function (err, val) { + // Add form data to annotation + newAnnot.properties.annotations = val; + console.log("inside formSchema.onSubmit of newAnnot object"); + console.log(newAnnot); + // Post annotation + annotools.addnewAnnot(newAnnot); + + // Hide Panel + jQuery('#panel').hide('slide'); + annotools.drawLayer.hide(); + annotools.addMouseEvents(); + + return false + }; + + var cancelAnnotation = function () { + console.log('cancel handler'); + jQuery('#panel').hide('slide'); + annotools.drawLayer.hide(); + annotools.addMouseEvents() + }; + + jQuery('#annotationsForm').jsonForm(formSchema) + }) +}; annotools.prototype.promptForAnalysis = function (annotools, analysisBox) { - var title = 'Analysis Tool' - var form = "' - var SM = new SimpleModal() - SM.addButton('Confirm', 'btn primary', function () { - var algorithm = $('algorithm').value - this.hide() - annotools.promptForParameters(annotools, analysisBox, algorithm) - }) - SM.addButton('Cancel', 'btn secondary', function () { - annotools.addMouseEvents() - this.hide() - return false - }) - SM.show({ - 'model': 'modal', - 'title': title, - 'contents': form - }) -} + var title = 'Analysis Tool'; + var form = "'; + var SM = new SimpleModal(); + SM.addButton('Confirm', 'btn primary', function () { + var algorithm = $('algorithm').value; + this.hide(); + annotools.promptForParameters(annotools, analysisBox, algorithm) + }); + SM.addButton('Cancel', 'btn secondary', function () { + annotools.addMouseEvents(); + this.hide(); + return false + }); + SM.show({ + 'model': 'modal', + 'title': title, + 'contents': form + }) +}; annotools.prototype.promptForParameters = function (annotools, analysisBox, algorithm) { - var title = 'Enter the parameters' - var form = '
' - var field = [] - var parameters = '{ ' - /*====================test samples, will need to be retrived from API calls===============*/ - var sample = '{ "param_1" : "text" , "param_2" : "text" }' - var sampleJson = JSON.parse(sample) - /*===================================*/ - switch (algorithm) { - case 'canny_edge': - for (var key in sampleJson) { - field.push(key) - form += "

" + key + "


" - parameters += '"' + key + '" : ' - parameters += '__' + key + '__, ' - } - break - case 'marching_cubes': - for (var key in sampleJson) { - field.push(key) - form += "

" + key + "


" - parameters += '"' + key + '" : ' - parameters += '__' + key + '__, ' - } - break - } - form += '
' - parameters = parameters.substring(0, parameters.length - 2) + ' }' - var SM = new SimpleModal() - SM.addButton('Confirm', 'btn primary', function () { - for (var i = 0; i < field.length; i++) { - var fieldElem = $$(document.getElementsByName(field[i])) - var replacement = '"' + $(field[i]).value + '"' - parameters = parameters.replace('__' + field[i] + '__', replacement) + var title = 'Enter the parameters'; + var form = '
'; + var field = []; + var parameters = '{ '; + /*====================test samples, will need to be retrived from API calls===============*/ + var sample = '{ "param_1" : "text" , "param_2" : "text" }'; + var sampleJson = JSON.parse(sample); + /*===================================*/ + switch (algorithm) { + case 'canny_edge': + for (var key in sampleJson) { + field.push(key); + form += "

" + key + "


"; + parameters += '"' + key + '" : '; + parameters += '__' + key + '__, ' + } + break; + case 'marching_cubes': + for (var key in sampleJson) { + field.push(key); + form += "

" + key + "


"; + parameters += '"' + key + '" : '; + parameters += '__' + key + '__, ' + } + break } - var submission = '{ "Algorithm" : "' + algorithm + '", "x" : "' + analysisBox.x + '", "y" : "' + analysisBox.y + '", "w" : "' + analysisBox.w + '", "h" : "' + analysisBox.h + '", "Parameters" : ' + parameters + ' }' - console.log(submission) - submission = JSON.parse(submission) - /*============after this point, submission is ready to be handed over to bindaas=========*/ - annotools.addMouseEvents() - this.hide() - return false - }) - SM.addButton('Cancel', 'btn secondary', function () { - annotools.addMouseEvents() - this.hide() - return false - }) - SM.show({ - 'model': 'modal', - 'title': title, - 'contents': form - }) -} + form += '
'; + parameters = parameters.substring(0, parameters.length - 2) + ' }'; + var SM = new SimpleModal(); + SM.addButton('Confirm', 'btn primary', function () { + for (var i = 0; i < field.length; i++) { + var fieldElem = $$(document.getElementsByName(field[i])); + var replacement = '"' + $(field[i]).value + '"'; + parameters = parameters.replace('__' + field[i] + '__', replacement) + } + var submission = '{ "Algorithm" : "' + algorithm + '", "x" : "' + analysisBox.x + '", "y" : "' + analysisBox.y + '", "w" : "' + analysisBox.w + '", "h" : "' + analysisBox.h + '", "Parameters" : ' + parameters + ' }'; + console.log(submission); + submission = JSON.parse(submission); + /*============after this point, submission is ready to be handed over to bindaas=========*/ + annotools.addMouseEvents(); + this.hide(); + return false + }); + SM.addButton('Cancel', 'btn secondary', function () { + annotools.addMouseEvents(); + this.hide(); + return false + }); + SM.show({ + 'model': 'modal', + 'title': title, + 'contents': form + }) +}; annotools.prototype.addMouseEvents = function () { - //console.log('adding mouse events') - // console.log(this.annotationHandler) - window.addEventListener('mousemove', this.annotationHandler.handleMouseMove, false) - //window.addEventListener('mousedown', this.annotationHandler.handleMouseDown, false) - //window.addEventListener('mouseup', this.annotationHandler.handleMouseUp, false) + //console.log('adding mouse events') + // console.log(this.annotationHandler) + window.addEventListener('mousemove', this.annotationHandler.handleMouseMove, false) + //window.addEventListener('mousedown', this.annotationHandler.handleMouseDown, false) + //window.addEventListener('mouseup', this.annotationHandler.handleMouseUp, false) // window.addEventListener('mouseup', this.getAnnot(), false) -} +}; annotools.prototype.removeMouseEvents = function () { - //console.log('removing events') - // console.log(this.annotationHandler) - window.removeEventListener('mousemove', this.annotationHandler.handleMouseMove, false) - //window.removeEventListener('mousedown', this.annotationHandler.handleMouseDown, false) - //window.removeEventListener('mouseup', this.annotationHandler.handleMouseUp, false) + //console.log('removing events') + // console.log(this.annotationHandler) + window.removeEventListener('mousemove', this.annotationHandler.handleMouseMove, false) + //window.removeEventListener('mousedown', this.annotationHandler.handleMouseDown, false) + //window.removeEventListener('mouseup', this.annotationHandler.handleMouseUp, false) // window.removeEventListener('mouseup', this.getAnnot(), false) -} - +}; -annotools.prototype.downloadROI = function(){ - this.showMessage() // Show Message - this.drawCanvas.removeEvents('mouseup') - this.drawCanvas.removeEvents('mousedown') - this.drawCanvas.removeEvents('mousemove') - this.drawLayer.show() // Show The Drawing Layer - /* ASHISH Disable quit - this.quitbutton.show() //Show The Quit Button - */ - this.magnifyGlass.hide() // Hide The Magnifying Tool - // this.container = document.id(this.canvas) //Get The Canvas Container - this.container = document.getElementsByClassName(this.canvas)[0] // Get The Canvas Container - // this.container = document.getElementById('container') //Get The Canvas Container - if (this.container) { - // var left = parseInt(this.container.offsetLeft), //Get The Container Location - var left = parseInt(this.container.getLeft()), // Get The Container Location - top = parseInt(this.container.offsetTop), - width = parseInt(this.container.offsetWidth), - height = parseInt(this.container.offsetHeight), - oleft = left, - otop = top, - owidth = width, - oheight = height - // console.log("left: " + left + " top: " + top + " width: " + width + " height: " + height) - if (left < 0) { - left= 0 - width = window.innerWidth - } // See Whether The Container is outside The Current ViewPort - if (top < 0) { - top = 0 - height = window.innerHeight +annotools.prototype.downloadROI = function () { + this.showMessage(); // Show Message + this.drawCanvas.removeEvents('mouseup'); + this.drawCanvas.removeEvents('mousedown'); + this.drawCanvas.removeEvents('mousemove'); + this.drawLayer.show(); // Show The Drawing Layer + /* ASHISH Disable quit + this.quitbutton.show() //Show The Quit Button + */ + this.magnifyGlass.hide(); // Hide The Magnifying Tool + // this.container = document.id(this.canvas) //Get The Canvas Container + this.container = document.getElementsByClassName(this.canvas)[0]; // Get The Canvas Container + // this.container = document.getElementById('container') //Get The Canvas Container + if (this.container) { + // var left = parseInt(this.container.offsetLeft), //Get The Container Location + var left = parseInt(this.container.getLeft()), // Get The Container Location + top = parseInt(this.container.offsetTop), + width = parseInt(this.container.offsetWidth), + height = parseInt(this.container.offsetHeight), + oleft = left, + otop = top, + owidth = width, + oheight = height; + // console.log("left: " + left + " top: " + top + " width: " + width + " height: " + height) + if (left < 0) { + left = 0; + width = window.innerWidth + } // See Whether The Container is outside The Current ViewPort + if (top < 0) { + top = 0; + height = window.innerHeight + } + // Recreate The CreateAnnotation Layer Because of The ViewPort Change Issue. + this.drawLayer.set({ + 'styles': { + left: left, + top: top, + width: width, + height: height + } + }); + // Create Canvas on the CreateAnnotation Layer + this.drawCanvas.set({ + width: width, + height: height + }); + // The canvas context + var ctx = this.drawCanvas.getContext('2d'); + + + this.removeMouseEvents(); + var started = false; + var min_x, min_y, max_x, max_y, w, h; + var startPosition; + this.drawCanvas.addEvent('mousedown', function (e) { + started = true; + startPosition = OpenSeadragon.getMousePosition(e.event); + x = startPosition.x; + y = startPosition.y + }); + + this.drawCanvas.addEvent('mousemove', function (e) { + if (started) { + ctx.clearRect(0, 0, this.drawCanvas.width, this.drawCanvas.height); + var currentMousePosition = OpenSeadragon.getMousePosition(e.event); + + min_x = Math.min(currentMousePosition.x, startPosition.x); + min_y = Math.min(currentMousePosition.y, startPosition.y); + max_x = Math.max(currentMousePosition.x, startPosition.x); + max_y = Math.max(currentMousePosition.y, startPosition.y); + w = Math.abs(max_x - min_x); + h = Math.abs(max_y - min_y); + ctx.strokeStyle = this.color; + ctx.fillStyle = 'rgba(255, 255, 255, 0.2)'; + ctx.fillRect(min_x, min_y, w, h); + ctx.strokeRect(min_x, min_y, w, h) + } + }.bind(this)); + + this.drawCanvas.addEvent('mouseup', function (e) { + started = false; + var finalMousePosition = new OpenSeadragon.getMousePosition(e.event); + + min_x = Math.min(finalMousePosition.x, startPosition.x); + min_y = Math.min(finalMousePosition.y, startPosition.y); + max_x = Math.max(finalMousePosition.x, startPosition.x); + max_y = Math.max(finalMousePosition.y, startPosition.y); + + var startRelativeMousePosition = new OpenSeadragon.Point(min_x, min_y).minus(OpenSeadragon.getElementOffset(viewer.canvas)); + var endRelativeMousePosition = new OpenSeadragon.Point(max_x, max_y).minus(OpenSeadragon.getElementOffset(viewer.canvas)); + var newAnnot = { + x: startRelativeMousePosition.x, + y: startRelativeMousePosition.y, + w: w, + h: h, + type: 'rect', + color: this.color, + loc: [] + }; + + var globalNumbers = JSON.parse(this.convertFromNative(newAnnot, endRelativeMousePosition)); + + newAnnot.x = globalNumbers.nativeX; + newAnnot.y = globalNumbers.nativeY; + newAnnot.w = globalNumbers.nativeW; + newAnnot.h = globalNumbers.nativeH; + var loc = []; + loc[0] = parseFloat(newAnnot.x); + loc[1] = parseFloat(newAnnot.y); + newAnnot.loc = loc; + + // convert to geojson + // var geoNewAnnot = this.convertRectToGeo(newAnnot) + geoNewAnnot = newAnnot; + this.promptForDownload(geoNewAnnot, 'new', this, ctx) + }.bind(this)) } - // Recreate The CreateAnnotation Layer Because of The ViewPort Change Issue. - this.drawLayer.set({ - 'styles': { - left: left, - top: top, - width: width, - height: height - } - }) - // Create Canvas on the CreateAnnotation Layer - this.drawCanvas.set({ - width: width, - height: height - }) - // The canvas context - var ctx = this.drawCanvas.getContext('2d') - - - this.removeMouseEvents() - var started = false - var min_x,min_y,max_x,max_y,w,h - var startPosition - this.drawCanvas.addEvent('mousedown', function (e) { - started = true - startPosition = OpenSeadragon.getMousePosition(e.event) - x = startPosition.x - y = startPosition.y - }) +}; - this.drawCanvas.addEvent('mousemove', function (e) { - if (started) { - ctx.clearRect(0, 0, this.drawCanvas.width, this.drawCanvas.height) - var currentMousePosition = OpenSeadragon.getMousePosition(e.event) - - min_x = Math.min(currentMousePosition.x, startPosition.x) - min_y = Math.min(currentMousePosition.y, startPosition.y) - max_x = Math.max(currentMousePosition.x, startPosition.x) - max_y = Math.max(currentMousePosition.y, startPosition.y) - w = Math.abs(max_x - min_x) - h = Math.abs(max_y - min_y) - ctx.strokeStyle = this.color - ctx.fillStyle = 'rgba(255, 255, 255, 0.2)' - ctx.fillRect(min_x, min_y, w, h) - ctx.strokeRect(min_x, min_y, w, h) - } - }.bind(this)) - this.drawCanvas.addEvent('mouseup', function (e) { - started = false - var finalMousePosition = new OpenSeadragon.getMousePosition(e.event) - - min_x = Math.min(finalMousePosition.x, startPosition.x) - min_y = Math.min(finalMousePosition.y, startPosition.y) - max_x = Math.max(finalMousePosition.x, startPosition.x) - max_y = Math.max(finalMousePosition.y, startPosition.y) - - var startRelativeMousePosition = new OpenSeadragon.Point(min_x, min_y).minus(OpenSeadragon.getElementOffset(viewer.canvas)) - var endRelativeMousePosition = new OpenSeadragon.Point(max_x, max_y).minus(OpenSeadragon.getElementOffset(viewer.canvas)) - var newAnnot = { - x: startRelativeMousePosition.x, - y: startRelativeMousePosition.y, - w: w, - h: h, - type: 'rect', - color: this.color, - loc: [] - } - - var globalNumbers = JSON.parse(this.convertFromNative(newAnnot, endRelativeMousePosition)) - - newAnnot.x = globalNumbers.nativeX - newAnnot.y = globalNumbers.nativeY - newAnnot.w = globalNumbers.nativeW - newAnnot.h = globalNumbers.nativeH - var loc = [] - loc[0] = parseFloat(newAnnot.x) - loc[1] = parseFloat(newAnnot.y) - newAnnot.loc = loc - - // convert to geojson - // var geoNewAnnot = this.convertRectToGeo(newAnnot) - geoNewAnnot = newAnnot - this.promptForDownload(geoNewAnnot, 'new', this, ctx) - }.bind(this)) - } -} +annotools.prototype.promptForDownload = function (newAnnot, mode, annotools, ctx) { + var panel = jQuery('#panel').show(); + var iid = this.iid; + var x = annotools.imagingHelper.physicalToDataX(annotools.imagingHelper.logicalToPhysicalX(newAnnot.x)); + var y = annotools.imagingHelper.physicalToDataY(annotools.imagingHelper.logicalToPhysicalY(newAnnot.y)); + var w = (annotools.imagingHelper.physicalToDataX(annotools.imagingHelper.logicalToPhysicalX((newAnnot.x + newAnnot.w)))) - x; + var h = (annotools.imagingHelper.physicalToDataY(annotools.imagingHelper.logicalToPhysicalY(newAnnot.y + newAnnot.h))) - y; + x = parseInt(x); + y = parseInt(y); + w = parseInt(w); + h = parseInt(h); + var max = 2000; + var url; + var iipSrv = "http://quip1.uhmc.sunysb.edu/fcgi-bin/iipsrv.fcgi?IIIF="; + console.log(fileLocation); + var fileLocationReal = fileLocation.substr(0, fileLocation.length - 4); + console.log(fileLocationReal); + if (w * h > max * max) { + w = max; + h = max; + url = iipSrv + fileLocationReal + "/" + x + "," + y + "," + w + "," + h + "/full/0/default.jpg"; -annotools.prototype.promptForDownload = function(newAnnot, mode, annotools, ctx) { - var panel = jQuery('#panel').show() - var iid = this.iid - var x = annotools.imagingHelper.physicalToDataX(annotools.imagingHelper.logicalToPhysicalX(newAnnot.x)) - var y = annotools.imagingHelper.physicalToDataY(annotools.imagingHelper.logicalToPhysicalY(newAnnot.y)) - var w = (annotools.imagingHelper.physicalToDataX(annotools.imagingHelper.logicalToPhysicalX((newAnnot.x + newAnnot.w)))) - x; - var h = (annotools.imagingHelper.physicalToDataY(annotools.imagingHelper.logicalToPhysicalY(newAnnot.y + newAnnot.h))) - y - x = parseInt(x) - y = parseInt(y) - w = parseInt(w) - h = parseInt(h) - var max = 2000; - var url; - var iipSrv = "http://quip1.uhmc.sunysb.edu/fcgi-bin/iipsrv.fcgi?IIIF="; - console.log(fileLocation); - var fileLocationReal = fileLocation.substr(0, fileLocation.length -4); - console.log(fileLocationReal); - if(w*h > max*max){ - w = max; - h = max; - - url = iipSrv + fileLocationReal + "/"+x+ ","+y+","+w+","+h +"/full/0/default.jpg"; - - panel.html(function () { - return "

Download ROI

  • x: " - + x + "
  • y: " - + y + "
  • w: " + w + "
  • h: " + h + "

Error! The ROI was too large. We've resized it to 2000 x 2000 tile
"; - }); + panel.html(function () { + return "

Download ROI

  • x: " + + x + "
  • y: " + + y + "
  • w: " + w + "
  • h: " + h + "

Error! The ROI was too large. We've resized it to 2000 x 2000 tile
"; + }); } else { - url = iipSrv + fileLocationReal + "/"+x+ ","+y+","+w+","+h +"/full/0/default.jpg"; + url = iipSrv + fileLocationReal + "/" + x + "," + y + "," + w + "," + h + "/full/0/default.jpg"; - panel.html(function () { - return "

Download ROI

  • x: " - + x + "
  • y: " - + y + "
  • w: " + w + "
  • h: " + h + "

"; - }); + panel.html(function () { + return "

Download ROI

  • x: " + + x + "
  • y: " + + y + "
  • w: " + w + "
  • h: " + h + "

"; + }); } - jQuery('#cancelWorkOrder').click(function () { - - jQuery('#panel').hide() - annotools.drawLayer.hide() - annotools.addMouseEvents() - }) - console.log(fileLocation); + jQuery('#cancelWorkOrder').click(function () { + + jQuery('#panel').hide(); + annotools.drawLayer.hide(); + annotools.addMouseEvents() + }); + console.log(fileLocation); console.log(fileLocation); console.log(url); - jQuery('#submitWorkOrder').click(function () { - - // annotools.drawCanvas.removeEvents('mouseup') - // annotools.drawCanvas.removeEvents('mousedown') - // annotools.drawCanvas.removeEvents('mousemove') - annotools.drawLayer.hide() - annotools.addMouseEvents() - // annotools.removeMouseEvents() - // annotools.getMultiAnnot(); - - var username = 'lastlegion' - var execution_id = jQuery('#order-execution_id').val() - var notes = jQuery('#order-notes').val() - var width = 48002; - var height = 35558; - - }.bind(newAnnot)) + jQuery('#submitWorkOrder').click(function () { -} + // annotools.drawCanvas.removeEvents('mouseup') + // annotools.drawCanvas.removeEvents('mousedown') + // annotools.drawCanvas.removeEvents('mousemove') + annotools.drawLayer.hide(); + annotools.addMouseEvents(); + // annotools.removeMouseEvents() + // annotools.getMultiAnnot(); + + var username = 'lastlegion'; + var execution_id = jQuery('#order-execution_id').val(); + var notes = jQuery('#order-notes').val(); + var width = 48002; + var height = 35558; + + }.bind(newAnnot)) + +}; -annotools.prototype.mergeStep1 = function() { +annotools.prototype.mergeStep1 = function () { console.log("mergeStep1"); var x1 = this.imagingHelper._viewportOrigin['x']; var y1 = this.imagingHelper._viewportOrigin['y']; var x2 = x1 + this.imagingHelper._viewportWidth; - var y2 = y1 + this.imagingHelper._viewportHeight; + var y2 = y1 + this.imagingHelper._viewportHeight; var physicalX1 = this.imagingHelper.logicalToPhysicalX(x1); var physicalY1 = this.imagingHelper.logicalToPhysicalY(y1); @@ -2337,23 +2370,24 @@ annotools.prototype.mergeStep1 = function() { var dataX2 = helper.physicalToDataX(physicalX2); var dataY2 = helper.physicalToDataY(physicalY2); - var area = (dataX2 - dataX1)*(dataY2-dataY1); - console.log("area", area); + var area = (dataX2 - dataX1) * (dataY2 - dataY1); + console.log("area", area); - var case_id = this.iid - var subject_id = case_id.substr(0,12); - if(subject_id.substr(0,4) != "TCGA"){ - //subject_id = ""; + var case_id = this.iid; + var subject_id = case_id.substr(0, 12); + if (subject_id.substr(0, 4) != "TCGA") { + //subject_id = ""; } - + var execution_id = annotool.execution_id; - var user=annotool.user; + var user = annotool.user; var d = new Date(); - var current_time=d.toLocaleString(); + var current_time = d.toLocaleString(); // get algorithm and color info var algo_and_color = this.getAlgorithmColorFromMenuTree(); - if (algo_and_color === null) { + //if no algorithm is selected, algo_and_color is false,otherwise algo_and_color has value; + if (!algo_and_color) { return false; } else { @@ -2361,124 +2395,125 @@ annotools.prototype.mergeStep1 = function() { var selected_color = algo_and_color.color; } - // add first vertice of rectangle to the end to ensure the loop is closed - var geoJSONTemplate = { - 'type': 'Feature', - 'parent_id': 'self', - 'randval': Math.random(), - 'geometry': { - 'type': 'Polygon', - 'coordinates': [ - [ + // add first vertice of rectangle to the end to ensure the loop is closed + var geoJSONTemplate = { + 'type': 'Feature', + 'parent_id': 'self', + 'randval': Math.random(), + 'geometry': { + 'type': 'Polygon', + 'coordinates': [ [ - x1, - y1 - ], - [ - x2, - y1 - ], - [ - x2, - y2 - ], - [ - x1, - y2 - ], - [ - x1, - y1 - ], - ] - ] - }, - 'normalized': true, - 'object_type': 'annotation', - 'properties': { - 'annotations': { - 'region' : '', - 'additional_annotation' : 'test', - 'additional_notes' : 'test', - 'secret' : 'human1' + [ + x1, + y1 + ], + [ + x2, + y1 + ], + [ + x2, + y2 + ], + [ + x1, + y2 + ], + [ + x1, + y1 + ], + ] + ] + }, + 'normalized': true, + 'object_type': 'annotation', + 'properties': { + 'annotations': { + 'region': '', + 'additional_annotation': 'test', + 'additional_notes': 'test', + 'secret': 'human1' + } + }, + 'footprint': area, + 'provenance': { + 'analysis': { + 'execution_id': execution_id, + 'study_id': '', + 'source': 'human', + 'computation': 'segmentation' + }, + 'image': { + 'case_id': case_id, + 'subject_id': subject_id + } + }, + 'date': Date.now(), + x: x1, + y: y1, + 'algorithm': selected_algorithm, + 'color': selected_color, + 'created_by': user, + 'created_on': current_time, + 'updated_by': '', + 'updated_on': '' + }; + + var self = this; + console.log('Save geoJSONTemplate function'); + console.log(geoJSONTemplate); + + jQuery.ajax({ + 'type': 'POST', + url: 'api/Data/getAnnotSpatial_sc.php', + data: geoJSONTemplate, + + success: function (res, err) { + console.log("response: "); + console.log(res); + + if (res == "unauthorized") { + alert("Error saving markup! Wrong secret"); + } else { + alert("Successfully saved markup!"); + //self.deleteAnnotationWithinRectangle(geoJSONTemplate); + //console.log("deleteAnnotationWithinRectangle"); + } + + console.log("err is:" + err); + self.getMultiAnnot(); + console.log('succesfully posted') } - }, - 'footprint': area, - 'provenance': { - 'analysis': { - 'execution_id': execution_id, - 'study_id': '', - 'source': 'human', - 'computation': 'segmentation' - }, - 'image': { - 'case_id': case_id, - 'subject_id': subject_id - } - }, - 'date': Date.now(), - x:x1, - y:y1, - 'algorithm':selected_algorithm, - 'color':selected_color, - 'created_by':user, - 'created_on':current_time, - 'updated_by':'', - 'updated_on':'' - } - - var self = this; - console.log('Save geoJSONTemplate function') - console.log(geoJSONTemplate) - - jQuery.ajax({ - 'type': 'POST', - url: 'api/Data/getAnnotSpatial_sc.php', - data: geoJSONTemplate, - - success: function (res, err) { - console.log("response: ") - console.log(res) - - if(res == "unauthorized"){ - alert("Error saving markup! Wrong secret"); - } else { - alert("Successfully saved markup!"); - //self.deleteAnnotationWithinRectangle(geoJSONTemplate); - //console.log("deleteAnnotationWithinRectangle"); - } - - console.log("err is:"+err) - self.getMultiAnnot(); - console.log('succesfully posted') - } - }) - -}//end of mergeStep1 func + }) +};//end of mergeStep1 func -annotools.prototype.deleteAnnotationWithinRectangle = function(newAnnot){ - var case_id= newAnnot.provenance.image.case_id; - var subject_id= newAnnot.provenance.image.subject_id; - var execution_id = newAnnot.provenance.analysis.execution_id; - console.log(execution_id); - - var x1=newAnnot.geometry.coordinates[0][0][0]; - var y1=newAnnot.geometry.coordinates[0][0][1]; - var x2=newAnnot.geometry.coordinates[0][2][0]; - var y2=newAnnot.geometry.coordinates[0][2][1]; - - var url1 = "api/Data/deleteAnnotationWithinRectangle.php?case_id="+ case_id + "&subject_id=" + subject_id + "&execution_id=" + execution_id +"&x1=" + x1+ "&y1=" + y1 + "&x2=" + x2 + "&y2=" + y2; - console.log(url1); - jQuery.ajax({ url: url1, - type: 'DELETE', - data:null, - success: function(data){ - console.log(data); - } - }); -}//end of deleteAnnotationWithinRectangle +annotools.prototype.deleteAnnotationWithinRectangle = function (newAnnot) { + var case_id = newAnnot.provenance.image.case_id; + var subject_id = newAnnot.provenance.image.subject_id; + var execution_id = newAnnot.provenance.analysis.execution_id; + console.log(execution_id); + + var x1 = newAnnot.geometry.coordinates[0][0][0]; + var y1 = newAnnot.geometry.coordinates[0][0][1]; + var x2 = newAnnot.geometry.coordinates[0][2][0]; + var y2 = newAnnot.geometry.coordinates[0][2][1]; + + var url1 = "api/Data/deleteAnnotationWithinRectangle.php?case_id=" + case_id + "&subject_id=" + subject_id + "&execution_id=" + execution_id + "&x1=" + x1 + "&y1=" + y1 + "&x2=" + x2 + "&y2=" + y2; + console.log(url1); + jQuery.ajax({ + url: url1, + type: 'DELETE', + data: null, + success: function (data) { + console.log(data); + } + }); + +};//end of deleteAnnotationWithinRectangle /** * Get Algorithm Color From Menu Tree @@ -2519,8 +2554,9 @@ annotools.prototype.getAlgorithmColorFromMenuTree = function () { var index2 = algorithm_title.indexOf("composite"); var index3 = algorithm_title.indexOf("dotnuclei"); var index4 = algorithm_title.indexOf("Heatmap"); + var index5 = algorithm_title.indexOf("Tumor"); - if (index1 === -1 && index2 === -1 && index3 === -1 && index4 === -1) { + if (index1 === -1 && index2 === -1 && index3 === -1 && index4 === -1 && index5 === -1) { algorithms.push(SELECTED_ALGORITHM_LIST[i]); algorithm_colors.push(SELECTED_ALGORITHM_COLOR[SELECTED_ALGORITHM_LIST[i]]); } @@ -2532,10 +2568,14 @@ annotools.prototype.getAlgorithmColorFromMenuTree = function () { if (num_algorithm === 0) { alert("No algorithms have been selected."); algo_and_color = null; + this.filter_algorithm = false; + return false; } else if (num_algorithm > 1 || num_algorithm < 1) { alert("Please select one and only one algorithm!"); algo_and_color = null; + this.filter_algorithm = false; + return false; } else { algo_and_color.color = algorithm_colors[0]; algo_and_color.algorithm = algorithms[0]; @@ -2545,57 +2585,39 @@ annotools.prototype.getAlgorithmColorFromMenuTree = function () { return algo_and_color; }; -annotools.prototype.generateCompositeDataset = function() { +annotools.prototype.generateCompositeDataset = function () { - alert("This function is temporarily disabled."); - return; - - var self = this; - - //image variables - var case_id=this.iid; - console.log('case_id is: '+ case_id); - - // user - var user = this.user; - console.log('user is: '+ user); - - - - var composite_order={ - "type" : "quip_composite_cwl", - "data" : { "name" : "segment_curation", "workflow" : {"user" : user, "case_id" : case_id}} - } - - jQuery.post('api/Data/compositeOrder.php', composite_order) + alert("This function is temporarily disabled."); + return; + + var self = this; + + //image variables + var case_id = this.iid; + console.log('case_id is: ' + case_id); + + // user + var user = this.user; + console.log('user is: ' + user); + + + var composite_order = { + "type": "quip_composite_cwl", + "data": {"name": "segment_curation", "workflow": {"user": user, "case_id": case_id}} + }; + + jQuery.post('api/Data/compositeOrder.php', composite_order) .done(function (res) { - var r = JSON.parse(res); - var id = r.id; - console.log("Composite Order submitted!, Job ID: "+id); - - //jQuery('#algorithmList').html(function(){ return "

Processing..."; }); - alert("Composite Order Processing...."); - - //self.toolBar.titleButton.hide() - //self.toolBar.ajaxBusy.show(); - - //start polling - /* - pollOrder(id, function(err, data){ - if(err){ - alert("Order failed! Couldn't process your order"); - self.toolBar.ajaxBusy.hide(); - self.toolBar.titleButton.show(); - } else{ - setTimeout(function(){ - self.toolBar.ajaxBusy.hide(); - self.toolBar.titleButton.show(); - self.getMultiAnnot(); - },2000) - } - }); - */ - + var r = JSON.parse(res); + var id = r.id; + console.log("Composite Order submitted!, Job ID: " + id); + + //jQuery('#algorithmList').html(function(){ return "

Processing..."; }); + alert("Composite Order Processing...."); + + //self.toolBar.titleButton.hide() + //self.toolBar.ajaxBusy.show(); + }) }//end of generateCompositeDataset @@ -2623,3 +2645,17 @@ function pollOrder(id, cb){ }); } +annotools.prototype.imageStatusUpdate = function(status){ + console.log(status); + var case_id=this.iid; + var url1 = "api/Data/imageStatusUpdate.php?case_id="+ case_id + "&status=" + status; + console.log(url1); + jQuery.ajax({ url: url1, + type: 'get', + data:null, + success: function(data){ + console.log(data); + } + }); +}//end of imageStatusUpdate(status) + diff --git a/js/annotationtoolslymph/AnnotationStore_Lymph.js b/js/annotationtoolslymph/AnnotationStore_Lymph.js index b31263e45..0bd5bbdb5 100644 --- a/js/annotationtoolslymph/AnnotationStore_Lymph.js +++ b/js/annotationtoolslymph/AnnotationStore_Lymph.js @@ -104,7 +104,7 @@ AnnotationStore.prototype.fetchAnnotations = function(x1,y1,x2,y2, footprint, al try{ var d = JSON.parse(data); - //console.log('retrived annots: ' + JSON.stringify(d[0])); + //console.log('retrieved annots: ' + JSON.stringify(d[0])); } catch (e){ callback({"error": "Error"}); } diff --git a/js/annotationtoolslymph/ToolBar_Lymph.js b/js/annotationtoolslymph/ToolBar_Lymph.js index 3ac110e7b..98bfa929c 100644 --- a/js/annotationtoolslymph/ToolBar_Lymph.js +++ b/js/annotationtoolslymph/ToolBar_Lymph.js @@ -1,561 +1,250 @@ -var ToolBar = function (element, options) { - // console.log(options) - this.annotools = options.annotool - // console.log(this.annotools) - this.FilterTools = options.FilterTools - this.source = element // The Tool Source Element - this.top = options.top || '0px' - this.left = options.left || '150px' // The Tool Location - this.height = options.height || '30px' - this.width = options.width || '270px' - this.zindex = options.zindex || '100' // To Make Sure The Tool Appears in the Front - - this.iid = options.iid || null - this.annotationActive = isAnnotationActive() - - //this.superuser = false; -} - -ToolBar.prototype.showMessage = function (msg) { - console.log(msg) -} - -ToolBar.prototype.algorithmSelector = function () { - var self = this - var ftree - xxx = [] -} - -//var available_colors = ['lime', 'red', 'blue', 'orange'] -var available_colors = ['#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f','#ff7f00','#cab2d6','#6a3d9a','#ffff99','#b15928']; -var algorithm_color = {} - -function goodalgo (data, status) { - // console.log(data) - - /* - data.push({ - - "title": "Human Test", - "provenance": { - "analysis_execution_id": "humantest" - } - }); - */ - - max_ver = 0 - for (i = 0;i < data.length;i++) { - var n = {} - data[i].title=data[i].provenance.analysis_execution_id; - n.title = "
" + data[i].title - n.key = i.toString() - n.refKey = data[i].provenance.analysis_execution_id - if (n.refKey.includes('lym_v')) { - ver = parseInt(n.refKey.split('lym_v')[1].split('-')[0]); - if (ver > max_ver) { - max_ver = ver - } - } - } - - var blob = [] - for (i = 0;i < data.length;i++) { - var n = {} - //console.log(data[i]) - data[i].title=data[i].provenance.analysis_execution_id; - n.title = "
" + data[i].title - n.key = i.toString() - n.refKey = data[i].provenance.analysis_execution_id - if (n.refKey == 'lym_v'+max_ver+'-high_res' || n.refKey == 'lym_v'+max_ver+'-low_res' || n.refKey == 'humanmark') { - n.selected = true - } - - //n.color = available_colors[i] - //algorithm_color[data[i].provenance.analysis_execution_id] = available_colors[i] - algorithm_color[data[i].provenance.analysis_execution_id] = available_colors[i%available_colors.length]; - blob.push(n) - } - ftree = jQuery('#tree').fancytree({ - source: [{ - title: 'Algorithms', key: '1', folder: true, - children: blob, - expanded: true - }], - minExpandLevel: 1, // 1: root node is not collapsible - activeVisible: true, // Make sure, active nodes are visible (expanded). - aria: false, // Enable WAI-ARIA support. - autoActivate: true, // Automatically activate a node when it is focused (using keys). - autoCollapse: false, // Automatically collapse all siblings, when a node is expanded. - autoScroll: false, // Automatically scroll nodes into visible area. - clickFolderMode: 4, // 1:activate, 2:expand, 3:activate and expand, 4:activate (dblclick expands) - checkbox: true, // Show checkboxes. - debugLevel: 2, // 0:quiet, 1:normal, 2:debug - disabled: false, // Disable control - focusOnSelect: false, // Set focus when node is checked by a mouse click - generateIds: false, // Generate id attributes like - idPrefix: 'ft_', // Used to generate node id´s like . - icons: true, // Display node icons. - keyboard: true, // Support keyboard navigation. - keyPathSeparator: '/', // Used by node.getKeyPath() and tree.loadKeyPath(). - minExpandLevel: 1, // 1: root node is not collapsible - quicksearch: false, // Navigate to next node by typing the first letters. - selectMode: 2, // 1:single, 2:multi, 3:multi-hier - tabbable: true, // Whole tree behaves as one single control - titlesTabbable: false, // Node titles can receive keyboard focus - beforeSelect: function (event, data) { - // A node is about to be selected: prevent this for folders: - if (data.node.isFolder()) { - return false - } - }, - select: function (event, data) { - jQuery('#tree').attr('algotree', true) - var node = data.node - - console.log('!SELECTED NODE : ' + node.title) - targetType = data.targetType - console.log(node); - annotool.getMultiAnnot() - } - }) - jQuery('#tree').attr('algotree', true) - - // Load weight - if (annotool.loadedWeight == false) { - annotool.loadHeatmapWeight(); - annotool.loadedWeight = true; - } - - - annotool.getMultiAnnot() -} - -/* -ToolBar.prototype.toggleAlgorithmSelector = function () { - if (!jQuery('#algosel').attr('eb')) { - jQuery('#algosel').attr('eb', true) - // console.log("initializing...") - jQuery('#algosel').css({ - 'width': '300px', - 'zIndex': 199, - 'visibility': 'hidden' - }) - jQuery('#algosel').on('mousedown', function (e) { - jQuery(this).addClass('draggable').parents().on('mousemove', function (e) { - jQuery('.draggable').offset({ - top: e.pageY - jQuery('.draggable').outerHeight() / 2, - left: e.pageX - jQuery('.draggable').outerWidth() / 2 - }).on('mouseup', function () { - jQuery(this).removeClass('draggable') - }) - }) - e.preventDefault() - }).on('mouseup', function () { - jQuery('.draggable').removeClass('draggable') - }) - } - if (jQuery('#algosel').css('visibility') == 'visible') { - jQuery('#algosel').css({ - 'visibility': 'hidden' - }) - } else { - jQuery('#algosel').css({ - 'visibility': 'visible' - }) - } - this.showMessage('Algorithm Selection Toggled') -} -*/ - -var ALGORITHM_LIST = {}; -var SELECTED_ALGORITHM_LIST = []; -var SELECTED_ALGORITHM_KEYS = []; -var AlgorithmSelectorHidden = true; - -ToolBar.prototype.toggleAlgorithmSelector = function () { - var self = this; - console.log("toggleAlgorithmSelector"); - //jQuery("#panel").show("slide"); - var url = 'api/Data/getAlgorithmsForImage.php?iid=' + self.iid; - - var htmlStr = "
Close

Select Algorithm

    "; - - jQuery.get(url, function (data) { - - d = JSON.parse(data) - - ALGORITHM_LIST = d; - for(var i=0; i < d.length; i++){ - //n.color = available_colors[i%7]; - //algorithm_color[d[i].provenance.analysis_execution_id] = available_colors[i%7] - algorithm_color[d[i].provenance.analysis_execution_id] = available_colors[i%available_colors.length]; - - htmlStr += "
  • "+d[i].provenance.analysis_execution_id - + "
  • "; - } - - htmlStr +="

"; - - jQuery("#panel").html(htmlStr); - - - - jQuery("#algorithmList input[type=checkbox]").each(function() { - - var elem = jQuery(this) - var id = (this).value*1; - for(var i=0; i < SELECTED_ALGORITHM_KEYS.length; i++){ - if(SELECTED_ALGORITHM_KEYS[i] == (id)){ - - elem.prop('checked', true); - } - } - - - }); - - self.annotools.getMultiAnnot(); - - jQuery('#algorithmList input[type=checkbox]').change(function() { - console.log("change"); - SELECTED_ALGORITHM_LIST = []; - SELECTED_ALGORITHM_KEYS = []; - jQuery("#algorithmList input:checked").each(function() { - console.log(ALGORITHM_LIST); - SELECTED_ALGORITHM_LIST.push(ALGORITHM_LIST[(this).value * 1].provenance.analysis_execution_id); - SELECTED_ALGORITHM_KEYS.push((this).value*1); - }); - - self.annotools.getMultiAnnot(); - - - }) - - /* - jQuery("#submitAlgorithms").click(function(){ - var selected= []; - SELECTED_ALGORITHM_LIST = []; - jQuery("#algorithmList input:checked").each(function() { - SELECTED_ALGORITHM_LIST.push(ALGORITHM_LIST[(this).value * 1].analysis.execution_id); - SELECTED_ALGORITHM_KEYS.push((this).value*1); - }); - - self.annotools.getMultiAnnot(); - jQuery("#panel").html(""); - jQuery("#panel").hide("slide"); - }); - */ - jQuery("#cancelAlgorithms").click(function(){ - jQuery("#panel").html(""); - jQuery("#panel").hide("slide"); - AlgorithmSelectorHidden = true; - }); - - jQuery("#closeFilterPanel").click(function(){ - jQuery("#panel").html(""); - jQuery("#panel").hide("slide"); - AlgorithmSelectorHidden = true; - }); - }); - if(AlgorithmSelectorHidden == true){ - jQuery("#panel").show("slide"); - AlgorithmSelectorHidden = false; - } else { - jQuery("#panel").html(""); - jQuery("#panel").hide("slide"); - - AlgorithmSelectorHidden = true; - } - -} - -ToolBar.prototype.setNormalMode = function() { - this.annotools.mode = 'normal'; - jQuery("canvas").css("cursor", "default"); - jQuery("#drawRectangleButton").removeClass('active'); - jQuery("#drawFreelineButton").removeClass('active'); - jQuery("#drawDotButton").removeClass("active"); // Dot Tool - jQuery("#freeLineMarkupButton").removeClass("active"); - jQuery("#markuppanel").hide(); - jQuery("#switchuserpanel").hide(); - this.annotools.drawLayer.hide() - this.annotools.addMouseEvents() -} - -ToolBar.prototype.createButtons = function () { - // this.tool = jQ(this.source) - var tool = jQuery('#' + 'tool') // Temporary dom element while we clean up mootools - var self = this - - - // Fetch algorithms for Image - jQuery(document).ready(function () { - // console.log(options) - // var self= this - - jQuery.get('api/Data/getAlgorithmsForImage.php?iid=' + self.iid, function (data) { - d = JSON.parse(data) - - //check version here start - var max_ver = 0 - for (var i = 0; i < d.length; i++) { - var n = {} - - n.refKey = d[i].provenance.analysis_execution_id; - //console.log("n.refKey: " + n.refKey); - if (n.refKey.includes('lym_v')) { - var ver = parseInt(n.refKey.split('lym_v')[1].split('-')[0]); - if (ver > max_ver) { - max_ver = ver; - } - } - } - //console.log("version: " + max_ver); - - for (var i = 0; i < d.length; i++) { - var n = {}; - - n.refKey = d[i].provenance.analysis_execution_id; - //console.log("n.refKey: " + n.refKey); - - if (n.refKey == 'lym_v'+max_ver+'-high_res' || n.refKey == 'lym_v'+max_ver+'-low_res' || n.refKey == 'humanmark') { - SELECTED_ALGORITHM_LIST.push(n.refKey); - SELECTED_ALGORITHM_KEYS.push(i); - } - } - - goodalgo(d, null) - }) - - // console.log("here") - jQuery('#submitbtn').click(function () { - var selKeys = jQuery('#tree').fancytree('getTree').getSelectedNodes() - var param = '' - for (i = 0;i < selKeys.length;i++) { - param = param + '&Val' + (i + 1).toString() + '=' + selKeys[i].title - } - }) - }) - - tool.css({ - 'position': 'absolute', - 'left': this.left, - 'top': this.top, - 'width': this.width, - 'height': this.height, - 'z-index': this.zindex - }) - - tool.addClass('annotools') // Update Styles - // this.tool.makeDraggable(); //Make it Draggable. - - - if (this.annotationActive) { - - /* - * Ganesh - * Mootools to Jquery for creation of toolbar buttons - */ - // docker intergration start - this.homebutton = jQuery('', { - src: 'images/ic_home_white_24px.svg', - class: 'toolButton firstToolButtonSpace inactive', - title: 'QuIP Home' - }); - tool.append(this.homebutton); - - this.micbutton = jQuery('', { - src: 'images/camic_vector.svg', - class: 'toolButton inactive', - title: 'caMicroscope' - }); - tool.append(this.micbutton); - - this.spacer1 = jQuery('', { - 'class': 'spacerButton inactive', - 'src': 'images/spacer_empty.svg' - }) - tool.append(this.spacer1) - // docker integration end - - this.filterbutton = jQuery('', { - 'title': 'Filter Markups', - 'class': 'toolButton inactive', - 'src': 'images/filter.svg' - }) - tool.append(this.filterbutton) // Filter Button - - this.hidebutton = jQuery('', { - 'title': 'Show/Hide Markups', - 'class': 'toolButton inactive', - 'src': 'images/hide.svg' - }) - tool.append(this.hidebutton) - - this.heatDownButton = jQuery('', { - 'title': 'Decrease Opacity', - 'class': 'toolButton inactive', - 'src': 'images/Opacity_down.svg', - 'id': 'heatDownButton', - }); - tool.append(this.heatDownButton); // Button for decreasing opacity - - this.heatUpButton = jQuery('', { - 'title': 'Increase Opacity', - 'class': 'toolButton inactive', - 'src': 'images/Opacity_up.svg', - 'id': 'heatUpButton', - }); - tool.append(this.heatUpButton); // Button for increasing opacity - - this.colorMapButton = jQuery('', { - 'class': 'colorMapButton', - 'title': 'ColorMap', - 'src': 'images/colors.svg' - }) - //tool.append(this.colorMapButton) - - //this.spacer = jQuery('', { - // 'class': 'spacerButton inactive', - // 'src': 'images/divider.svg' - //}) - //tool.append(this.spacer) - - this.showWeightPanel = jQuery('', { - 'title': 'Show Weight Panel', - 'class': 'toolButton inactive', - 'src': 'images/Heatmap.svg', - 'id': 'showWeightPanel', - }); - tool.append(this.showWeightPanel); // Button for showing the weight panel - - this.freeMarkupButton = jQuery('', { - 'title': 'Free Line Markup', - 'class': 'toolButton inactive', - 'src': 'images/pencil.svg', - 'id': 'freeLineMarkupButton' - }) - tool.append(this.freeMarkupButton) // Markup Pencil Tool - - this.spacer2 = jQuery('', { - 'class': 'spacerButton inactive', - 'src': 'images/spacer_empty.svg' - }) - tool.append(this.spacer2) - - this.switchUserButton = jQuery('', { - 'title': 'Switch User', - 'class': 'toolButton inactive', - 'src': 'images/switch_user.svg', - 'id': 'switchUserButton' - }); - tool.append(this.switchUserButton); // Button for switch user - - - /* - * Event handlers on click for the buttons +/** + * TOOLBAR + * LYMPHOCYTE APP + */ +$.getScript('shared/ToolBar.js', function () { + + /** + * Create Buttons */ - this.homebutton.on('click', function(){ - window.location.href = "/select.php"; - }.bind(this)) - - /* - this.micbutton.on('click', function(){ - window.location.href = "/camicroscope/osdCamicroscope.php?tissueId=" + this.iid; - }.bind(this)) - */ - - - this.micbutton.on('click', function () { - var tissueId = this.iid; - var x1 = annotool.imagingHelper._viewportOrigin['x']; - var y1 = annotool.imagingHelper._viewportOrigin['y']; - var x2 = x1 + annotool.imagingHelper._viewportWidth; - var y2 = y1 + annotool.imagingHelper._viewportHeight; - var zoom = viewer.viewport.getZoom(); - var width,height; - - //get image width and height - var url = 'api/Data/getImageInfoByCaseID.php?case_id=' + tissueId; - jQuery.get(url, function (data) { - //console.log(data); - try { - this_image = JSON.parse(data); - width = this_image[0].width; - height = this_image[0].height; - var x= parseInt(((x1+x2)/2.0)*width); - var y= parseInt(((y1+y2)/2.0)*height); - window.location.href = "/camicroscope/osdCamicroscope.php?tissueId=" + tissueId + "&x=" + x + "&y=" + y + "&zoom=" + zoom; - } catch (error){ - window.location.href = "/camicroscope/osdCamicroscope.php?tissueId=" + tissueId; - } - }) - }.bind(this)) - - this.hidebutton.on('click', function () { - this.annotools.toggleMarkups() - }.bind(this)) + ToolBar.prototype.createButtons = function () { + + // this.tool = jQ(this.source) + var tool = jQuery('#' + 'tool'); // Temporary dom element while we clean up mootools + var self = this; + + // Fetch algorithms for Image + jQuery(document).ready(function () { + // console.log(options) + // var self= this + + jQuery.get('api/Data/getAlgorithmsForImage.php?iid=' + self.iid, function (data) { + d = JSON.parse(data); + + // check version here start + var max_ver = 0; + for (var i = 0; i < d.length; i++) { + var n = {}; + + n.refKey = d[i].provenance.analysis_execution_id; + // console.log("n.refKey: " + n.refKey); + if (n.refKey.includes('lym_v')) { + var ver = parseInt(n.refKey.split('lym_v')[1].split('-')[0]); + if (ver > max_ver) { + max_ver = ver; + } + } + } + // console.log("version: " + max_ver); - this.filterbutton.on('click', function () { - this.toggleAlgorithmSelector() - // this.removeMouseEvents() - // this.promptForAnnotation(null, "filter", this, null) - }.bind(this)) + for (var i = 0; i < d.length; i++) { + var n = {}; - this.heatUpButton.on('click', function () { - this.annotools.heatmap_opacity = Math.min(1, this.annotools.heatmap_opacity + 0.1); - this.annotools.getMultiAnnot(); - }.bind(this)) + n.refKey = d[i].provenance.analysis_execution_id; + // console.log("n.refKey: " + n.refKey); - this.heatDownButton.on('click', function () { - this.annotools.heatmap_opacity = Math.max(0, this.annotools.heatmap_opacity - 0.1); - this.annotools.getMultiAnnot(); - }.bind(this)) + if (n.refKey == 'lym_v' + max_ver + '-high_res' || n.refKey == 'lym_v' + max_ver + '-low_res' || n.refKey == 'humanmark') { + SELECTED_ALGORITHM_LIST.push(n.refKey); + SELECTED_ALGORITHM_KEYS.push(i); + } + } - /* - this.switchUserButton.on('click', function () { - if (this.superuser) { - if (jQuery('#switchuserpanel').is(":visible")) - jQuery('#switchuserpanel').hide(); - else - jQuery('#switchuserpanel').show(); - } else { - alert("You are not a super user. A super user can review and change other people's annotations. To apply for the super user privilege. please contact Le Hou (le.hou@stonybrook.edu)."); - } - }.bind(this)) - */ - - this.switchUserButton.on('click', function () { - if (this.annotools.lymphSuperuser) { - if (jQuery('#switchuserpanel').is(":visible")) - jQuery('#switchuserpanel').hide(); - else - jQuery('#switchuserpanel').show(); - } else { - alert("You are not a super user. A super user can review and change other people's annotations. To apply for the super user privilege. please contact your QuIP app administrator."); - } - }.bind(this)) + goodalgo(d, null); + }); + + jQuery('#submitbtn').click(function () { + var selKeys = jQuery('#tree').fancytree('getTree').getSelectedNodes(); + var param = ''; + for (i = 0; i < selKeys.length; i++) { + param = param + '&Val' + (i + 1).toString() + '=' + selKeys[i].title + } + }); + }); + + tool.css({ + 'position': 'absolute', + 'left': this.left, + 'top': this.top, + 'width': this.width, + 'height': this.height, + 'z-index': this.zindex + }); + + tool.addClass('annotools'); // Update Styles + // this.tool.makeDraggable(); //Make it Draggable. + + /** + * Set up Toolbar buttons + */ + if (this.annotationActive) { + + /* Go home, go camicro */ + this.homebutton = jQuery('', { + title: 'QuIP Home', + class: 'toolButton firstToolButtonSpace inactive', + src: 'images/ic_home_white_24px.svg' + }); + tool.append(this.homebutton); + + this.micbutton = jQuery('', { + title: 'caMicroscope', + class: 'toolButton inactive', + src: 'images/camic_vector.svg' + }); + tool.append(this.micbutton); + + /* space */ + this.spacer1 = jQuery('', { + 'class': 'spacerButton inactive', + 'src': 'images/spacer_empty.svg' + }); + tool.append(this.spacer1); + + /* App tools */ + this.filterbutton = jQuery('', { + 'title': 'Filter Markups', + 'class': 'toolButton inactive', + 'src': 'images/filter.svg' + }); + tool.append(this.filterbutton); // Filter Button + + + this.heatDownButton = jQuery('', { + 'title': 'Decrease Opacity', + 'class': 'toolButton inactive', + 'src': 'images/Opacity_down.svg', + 'id': 'heatDownButton' + }); + tool.append(this.heatDownButton); // Button for decreasing opacity + + this.heatUpButton = jQuery('', { + 'title': 'Increase Opacity', + 'class': 'toolButton inactive', + 'src': 'images/Opacity_up.svg', + 'id': 'heatUpButton' + }); + tool.append(this.heatUpButton); // Button for increasing opacity + + this.showWeightPanel = jQuery('', { + 'title': 'Show Weight Panel', + 'class': 'toolButton inactive', + 'src': 'images/Heatmap.svg', + 'id': 'showWeightPanel' + }); + tool.append(this.showWeightPanel); // Button for showing the weight panel + + this.freeMarkupButton = jQuery('', { + 'title': 'Free Line Markup', + 'class': 'toolButton inactive', + 'src': 'images/pencil.svg', + 'id': 'freeLineMarkupButton' + }); + tool.append(this.freeMarkupButton); // Markup Pencil Tool + + /* space - next thing unavailable atm */ + tool.append(jQuery('', { + 'class': 'spacerButton inactive', + 'src': 'images/spacer_empty.svg' + })); + + this.switchUserButton = jQuery('', { + 'title': 'Switch User', + 'class': 'toolButton inactive', + 'src': 'images/switch_user.svg', + 'id': 'switchUserButton' + }); + tool.append(this.switchUserButton); // Button for switch user + + + /* + * Event handlers for toolbar buttons + */ + this.homebutton.on('click', function () { + window.location.href = "/select.php"; + }.bind(this)); + + + this.micbutton.on('click', function () { + var tissueId = this.iid; + var x1 = annotool.imagingHelper._viewportOrigin['x']; + var y1 = annotool.imagingHelper._viewportOrigin['y']; + var x2 = x1 + annotool.imagingHelper._viewportWidth; + var y2 = y1 + annotool.imagingHelper._viewportHeight; + var zoom = viewer.viewport.getZoom(); + var width, height; + //get image width and height + var url = 'api/Data/getImageInfoByCaseID.php?case_id=' + tissueId; + jQuery.get(url, function (data) { + try { + this_image = JSON.parse(data); + width = this_image[0].width; + height = this_image[0].height; + var x = parseInt(((x1 + x2) / 2.0) * width); + var y = parseInt(((y1 + y2) / 2.0) * height); + window.location.href = "/camicroscope/osdCamicroscope.php?tissueId=" + tissueId + "&x=" + x + "&y=" + y + "&zoom=" + zoom; + } catch (error) { + window.location.href = "/camicroscope/osdCamicroscope.php?tissueId=" + tissueId; + } + }) + }.bind(this)); + + + this.filterbutton.on('click', function () { + this.toggleAlgorithmSelector() + // this.removeMouseEvents() + // this.promptForAnnotation(null, "filter", this, null) + }.bind(this)); + + this.heatUpButton.on('click', function () { + this.annotools.heatmap_opacity = Math.min(1, this.annotools.heatmap_opacity + 0.1); + this.annotools.getMultiAnnot(); + }.bind(this)); + + this.heatDownButton.on('click', function () { + this.annotools.heatmap_opacity = Math.max(0, this.annotools.heatmap_opacity - 0.1); + this.annotools.getMultiAnnot(); + }.bind(this)); + + this.switchUserButton.on('click', function () { + if (this.annotools.lymphSuperuser) { + if (jQuery('#switchuserpanel').is(":visible")) + jQuery('#switchuserpanel').hide(); + else + jQuery('#switchuserpanel').show(); + } else { + alert("You are not a super user. A super user can review and change other people's annotations. To apply for the super user privilege. please contact your QuIP app administrator."); + } + }.bind(this)); this.showWeightPanel.on('click', function () { console.log('click on showing weight panel'); - if (jQuery('#weightpanel').is(":visible")) - { - jQuery('#weightpanel').hide(); - } - else - { - console.log(this.annotools.heat_weight); - jQuery('#weightpanel').show(); - } + console.log(appid); + var panelToShow = "#weightpanel"; + if (appid == "qualheat") { + panelToShow = "#qualitypanel"; + } + if(appid != "qualheat") { + if (jQuery(panelToShow).is(":visible")) + { + jQuery(panelToShow).hide(); + } + else + { + console.log(this.annotools.heat_weight); + jQuery(panelToShow).show(); + } + } else { + alert("This feature temporarily disabled in this app.") + } }.bind(this)) - this.freeMarkupButton.on('click', function () { - if(this.annotools.mode == 'free_markup'){ - this.setNormalMode(); - } else { - //set pencil mode - this.annotools.mode = 'free_markup' - this.annotools.drawMarkups() + this.freeMarkupButton.on('click', function () { + if (this.annotools.mode == 'free_markup') { + this.setNormalMode(); + } else { + //set pencil mode + this.annotools.mode = 'free_markup'; + this.annotools.drawMarkups(); jQuery("canvas").css("cursor", "crosshair"); //jQuery("drawFreelineButton").css("opacity", 1); @@ -563,10 +252,17 @@ ToolBar.prototype.createButtons = function () { jQuery("#drawDotButton").removeClass("active"); // Dot Tool jQuery("#drawFreelineButton").removeClass("active"); jQuery("#freeLineMarkupButton").addClass("active"); - jQuery("#markuppanel").show(); - + if (appid == "qualheat") { + jQuery("#qualitymarkuppanel").show(); + jQuery("#AlgoA").checked = true; + + } else { + jQuery("#markuppanel").show(); + document.getElementById('LymPos').checked = true; + } + // Check if being on moving mode --> switch to drawing mode - if (document.getElementById("rb_Moving").checked) { + if (document.getElementById("rb_Moving").checked||appid!="qualheat") { console.log('do switching'); document.getElementById('rb_Moving').checked = false; document.getElementById('LymPos').checked = true; @@ -575,70 +271,47 @@ ToolBar.prototype.createButtons = function () { }.bind(this)) - var toolButtons = jQuery('.toolButton') - toolButtons.each(function () { - jQuery(this).on({ - 'mouseenter': function () { - this.addClass('selected') - }, - 'mouseleave': function () { - this.removeClass('selected') + var toolButtons = jQuery('.toolButton'); + toolButtons.each(function () { + jQuery(this).on({ + 'mouseenter': function () { + // highlight button + this.addClass('selected') + }, + 'mouseleave': function () { + // un-highlight button + this.removeClass('selected') + } + }) + }) + } - }) - }) - - /* - for (var i = 0; i < toolButtons.length; i++) { - toolButtons[i].on({ - 'mouseenter': function () { - this.addClass('selected') - }, - 'mouseleave': function () { - this.removeClass('selected') - } - }) - } - */ - - /* - * Ganesh: Using the Mootools version as the jquery version breaks things - * - this.messageBox = jQuery('
', { - 'id': 'messageBox' - }) - jQuery("body").append(this.messageBox) - */ - - } - this.ajaxBusy = jQuery('', { - 'class': 'colorMapButton', - 'id': 'ajaxBusy', - 'style': 'scale(0.5, 1)', - 'src': 'images/progress_bar.gif' - }) - tool.append(this.ajaxBusy) - this.ajaxBusy.hide() - - this.titleButton = jQuery('

', { - 'class': 'titleButton', - 'text': 'caMic Lymphocyte App' - }) - tool.append(this.titleButton) - - this.iidbutton = jQuery('

', { - 'class': 'iidButton', - 'text': 'Case ID: ' + this.iid - }) - tool.append(this.iidbutton) - - /* ASHISH - disable quit button - this.quitbutton = new Element('img', { - 'title': 'quit', - 'class': 'toolButton', - 'src': 'images/quit.svg' - }).inject(this.tool) //Quit Button - */ - if (this.annotationActive) { - } -} + this.ajaxBusy = jQuery('', { + 'class': 'colorMapButton', + 'id': 'ajaxBusy', + 'style': 'scale(0.5, 1)', + 'src': 'images/progress_bar.gif' + }); + tool.append(this.ajaxBusy); + this.ajaxBusy.hide(); + + this.titleButton = jQuery('

', { + 'class': 'titleButton', + 'id': 'titleButton', + 'text': 'caMic Lymphocyte App' + }); + tool.append(this.titleButton); + + this.iidbutton = jQuery('

', { + 'class': 'iidButton', + 'text': 'Display ID: ' + this.displayId + }); + tool.append(this.iidbutton); + + if (this.annotationActive) { + // empty block + } + }; + +}); diff --git a/js/annotationtoolslymph/annotools-openseajax-handler-lymph.js b/js/annotationtoolslymph/annotools-openseajax-handler-lymph.js index bb7dbdf7c..e86130a6a 100644 --- a/js/annotationtoolslymph/annotools-openseajax-handler-lymph.js +++ b/js/annotationtoolslymph/annotools-openseajax-handler-lymph.js @@ -11,480 +11,493 @@ Unless required by applicable law or agreed to in writing, software distributed */ -var AnnotoolsOpenSeadragonHandler = function(viewer, options){ - - this.viewer = viewer; - this.state = 'none'; - this.stateTarget = null; - this.stateOrigin = null; - this.scale = options.ratio || 1.3; - this.lastCenter = {x: 0, y: 0}; - this.objectCenterPts = {}; - this.originalCoords = []; - this.originalDivCoords = []; - this.zoom = viewer.viewport.getZoom(); - this.zoomBase = viewer.viewport.getZoom(); - this.zooming = false; - this.panning = false; - this.animateWaitTime = options.animateWaitTime || 300; - - //this._setupOpenSeadragonButtonHandlers(); - - // global object reference used when the "this" object is referring to the window - window.annotationHandler = this; - }; - - /* - Redefines the button handlers from the OpenSeadragon button bar - for the onRelease event. Handles Zoom in, Zoom out, and Home - buttons. - */ - AnnotoolsOpenSeadragonHandler.prototype._setupOpenSeadragonButtonHandlers= function() { - - for (var i = 0; i < this.viewer.buttons.buttons.length; i++) { - var button = this.viewer.buttons.buttons[i]; - if (button.tooltip.toLowerCase() == "zoom in") { - var onZoomInRelease = button.onRelease; - var zoomIn = this.handleZoomIn; - button.onRelease = function(args){ +var AnnotoolsOpenSeadragonHandler = function (viewer, options) { + + this.viewer = viewer; + this.state = 'none'; + this.stateTarget = null; + this.stateOrigin = null; + this.scale = options.ratio || 1.3; + this.lastCenter = {x: 0, y: 0}; + this.objectCenterPts = {}; + this.originalCoords = []; + this.originalDivCoords = []; + this.zoom = viewer.viewport.getZoom(); + this.zoomBase = viewer.viewport.getZoom(); + this.zooming = false; + this.panning = false; + this.animateWaitTime = options.animateWaitTime || 300; + + //this._setupOpenSeadragonButtonHandlers(); + + // global object reference used when the "this" object is referring to the window + window.annotationHandler = this; +}; +/* + Redefines the button handlers from the OpenSeadragon button bar + for the onRelease event. Handles Zoom in, Zoom out, and Home + buttons. +*/ +AnnotoolsOpenSeadragonHandler.prototype._setupOpenSeadragonButtonHandlers = function () { + + for (var i = 0; i < this.viewer.buttons.buttons.length; i++) { + var button = this.viewer.buttons.buttons[i]; + if (button.tooltip.toLowerCase() == "zoom in") { + var onZoomInRelease = button.onRelease; + var zoomIn = this.handleZoomIn; + button.onRelease = function (args) { + + $$('svg')[0].setStyle('opacity', 1); + onZoomInRelease(args); + setTimeout(function () { + //zoomIn(); + $$('svg')[0].setStyle('opacity', 1); + }, annotationHandler.animateWaitTime); + }; + + } + else if (button.tooltip.toLowerCase() == "zoom out") { + var onZoomOutRelease = button.onRelease; + var zoomOut = this.handleZoomOut; + button.onRelease = function (args) { + + $$('svg')[0].setStyle('opacity', 0); + onZoomOutRelease(args); + setTimeout(function () { + //zoomOut(); $$('svg')[0].setStyle('opacity', 1); - onZoomInRelease(args); - setTimeout(function() { - //zoomIn(); - $$('svg')[0].setStyle('opacity', 1); - }, annotationHandler.animateWaitTime); - }; + }, annotationHandler.animateWaitTime); + }; + + } + + + } + +}.protect(); + +AnnotoolsOpenSeadragonHandler.prototype.goHome = function (annot) { + + annot.getAnnot(); +}; + +AnnotoolsOpenSeadragonHandler.prototype.handleZoomIn = function (annot) { + zooming = true; + console.log("handleZoomIn"); + var center = viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)); + if (annotationHandler.lastCenter.x != center.x || annotationHandler.lastCenter.y != center.y) { + scale = 1.3; + annotationHandler.zoom++; + var centerPt = + viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)); + $('originpt').setProperty('cx', centerPt.x); + $('originpt').setProperty('cy', centerPt.y); + + + for (var i = 0; i < $('viewport').getChildren().length; i++) { + + var object = $('viewport').getChildren()[i]; + //var centerPt = $('center')[0]; + var bbox = object.getBBox(); + + var newLocation = viewer.viewport.pixelFromPoint(annotationHandler.objectCenterPts[i]); + + var distance = newLocation.distanceTo(center); + if (object.tagName == "ellipse") { + + object.setAttribute("rx", (bbox.width / 2) * scale); + object.setAttribute("ry", (bbox.height / 2) * scale); + object.setAttribute("cx", newLocation.x); + object.setAttribute("cy", newLocation.y); + + } + else if (object.tagName == "rect") { + + object.setAttribute("width", (bbox.width) * scale); + object.setAttribute("height", (bbox.height) * scale); + object.setAttribute("x", newLocation.x - (bbox.width / 2) * scale); + object.setAttribute("y", newLocation.y - (bbox.height / 2) * scale); } - else if (button.tooltip.toLowerCase() == "zoom out") { - var onZoomOutRelease = button.onRelease; - var zoomOut = this.handleZoomOut; - button.onRelease = function(args){ - - $$('svg')[0].setStyle('opacity', 0); - onZoomOutRelease(args); - setTimeout(function() { - //zoomOut(); - $$('svg')[0].setStyle('opacity', 1); - }, annotationHandler.animateWaitTime); - }; + else { + + var points = String.split(object.getAttribute("points").trim(), ' '); + var newLocationRelPt = viewer.viewport.pointFromPixel(newLocation); + var distances = annotationHandler.originalCoords[i].distances; + var pointsStr = ""; + for (var j = 0; j < distances.length - 1; j++) { + var pointPair = distances[j].plus(newLocationRelPt); + var pixelPoint = viewer.viewport.pixelFromPoint(pointPair); + pointsStr += pixelPoint.x + "," + pixelPoint.y + " "; + + } + object.setAttribute("points", pointsStr); } + var div = $$('div.annotcontainer')[i]; + div.style.left = newLocation.x - (bbox.width / 2) * scale + "px"; + div.style.top = newLocation.y - (bbox.height / 2) * scale + "px"; + div.style.width = (bbox.width) * scale + "px"; + div.style.height = (bbox.height) * scale + "px"; + } + } + + annotationHandler.lastCenter = center; + zooming = false; +}; + +AnnotoolsOpenSeadragonHandler.prototype.handleZoomOut = function () { + zooming = true; + var center = viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)); + console.log("handleZoomOut"); + if (annotationHandler.lastCenter.x != center.x || annotationHandler.lastCenter.y != center.y) { + scale = 1 / 1.3; + annotationHandler.zoom--; + + var centerPt = + viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)); + $('originpt').setProperty('cx', centerPt.x); + $('originpt').setProperty('cy', centerPt.y); + + for (var i = 0; i < $('viewport').getChildren().length; i++) { + + var object = $('viewport').getChildren()[i]; + var bbox = object.getBBox(); + + var newLocation = viewer.viewport.pixelFromPoint(annotationHandler.objectCenterPts[i]); + + if (object.tagName == "ellipse") { + + object.setAttribute("rx", (bbox.width / 2) * scale); + object.setAttribute("ry", (bbox.height / 2) * scale); + object.setAttribute("cx", newLocation.x); + object.setAttribute("cy", newLocation.y); + + } + else if (object.tagName == "rect") { + + object.setAttribute("width", (bbox.width) * scale); + object.setAttribute("height", (bbox.height) * scale); + object.setAttribute("x", newLocation.x - (bbox.width / 2) * scale); + object.setAttribute("y", newLocation.y - (bbox.height / 2) * scale); + + } + else { + + var points = String.split(object.getAttribute("points").trim(), ' '); + var newLocationRelPt = viewer.viewport.pointFromPixel(newLocation); + var distances = annotationHandler.originalCoords[i].distances; + var pointsStr = ""; + for (var j = 0; j < distances.length - 1; j++) { + var pointPair = distances[j].plus(newLocationRelPt); + var pixelPoint = viewer.viewport.pixelFromPoint(pointPair); + pointsStr += pixelPoint.x + "," + pixelPoint.y + " "; + + } + object.setAttribute("points", pointsStr); + + } + var div = $$('div.annotcontainer')[i]; + div.style.left = newLocation.x - (bbox.width / 2) * scale + "px"; + div.style.top = newLocation.y - (bbox.height / 2) * scale + "px"; + div.style.width = (bbox.width) * scale + "px"; + div.style.height = (bbox.height) * scale + "px"; + + + } + + } + + annotationHandler.lastCenter = center; + zooming = false; +}; + +AnnotoolsOpenSeadragonHandler.prototype.handleMouseMove = function (evt) { + if (evt.preventDefault) + evt.preventDefault(); + + if (this.state == 'pan') { + //$('svg')[0].hide(); + if ($$('svg')[0]) { + $$('svg')[0].setStyle('opacity', 0); + } + var pixel = OpenSeadragon.getMousePosition(evt).minus + (OpenSeadragon.getElementPosition(viewer.element)); + var point = viewer.viewport.pointFromPixel(pixel); + } + + +}; + +AnnotoolsOpenSeadragonHandler.prototype.handleMouseUp = function (evt) { + + //if (evt.target.tagName.toLowerCase() == "button" || evt.target.tagName.toLowerCase() == "div") { + if (evt.target.tagName.toLowerCase() == "button") { - }.protect(); - - AnnotoolsOpenSeadragonHandler.prototype.goHome= function(annot) { - - annot.getAnnot(); - }; - - AnnotoolsOpenSeadragonHandler.prototype.handleZoomIn= function(annot) { - zooming = true; - console.log("handleZoomIn"); - var center = viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5,.5)); - if (annotationHandler.lastCenter.x != center.x || annotationHandler.lastCenter.y != center.y) { - scale = 1.3; - annotationHandler.zoom++; - var centerPt = - viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5,.5)); - $('originpt').setProperty('cx',centerPt.x); - $('originpt').setProperty('cy',centerPt.y); - - - for (var i = 0; i < $('viewport').getChildren().length; i++) { - - var object = $('viewport').getChildren()[i]; - //var centerPt = $('center')[0]; - var bbox = object.getBBox(); - - var newLocation = viewer.viewport.pixelFromPoint(annotationHandler.objectCenterPts[i]); - - var distance = newLocation.distanceTo(center); - if (object.tagName == "ellipse") { - - object.setAttribute("rx", (bbox.width/2)*scale); - object.setAttribute("ry", (bbox.height/2)*scale); - object.setAttribute("cx", newLocation.x); - object.setAttribute("cy", newLocation.y); - - } - else if (object.tagName == "rect") { - - object.setAttribute("width", (bbox.width)*scale); - object.setAttribute("height", (bbox.height)*scale); - object.setAttribute("x", newLocation.x-(bbox.width/2)*scale); - object.setAttribute("y", newLocation.y-(bbox.height/2)*scale); - - } - else { - - var points = String.split(object.getAttribute("points").trim(), ' '); - var newLocationRelPt = viewer.viewport.pointFromPixel(newLocation); - var distances = annotationHandler.originalCoords[i].distances; - var pointsStr = ""; - for (var j = 0; j < distances.length-1; j++) { - var pointPair = distances[j].plus(newLocationRelPt); - var pixelPoint = viewer.viewport.pixelFromPoint(pointPair); - pointsStr += pixelPoint.x + "," + pixelPoint.y + " "; - - } - object.setAttribute("points", pointsStr); - - } - - var div = $$('div.annotcontainer')[i]; - div.style.left = newLocation.x-(bbox.width/2)*scale + "px"; - div.style.top = newLocation.y-(bbox.height/2)*scale + "px"; - div.style.width = (bbox.width)*scale + "px"; - div.style.height = (bbox.height)*scale + "px"; - - - - } - } - - annotationHandler.lastCenter = center; - zooming = false; - }; - - AnnotoolsOpenSeadragonHandler.prototype.handleZoomOut= function() { - zooming = true; - var center = viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5,.5)); - console.log("handleZoomOut"); - if (annotationHandler.lastCenter.x != center.x || annotationHandler.lastCenter.y != center.y) { - scale = 1/1.3; - annotationHandler.zoom--; - - var centerPt = - viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5,.5)); - $('originpt').setProperty('cx',centerPt.x); - $('originpt').setProperty('cy',centerPt.y); - - for (var i = 0; i < $('viewport').getChildren().length; i++) { - - var object = $('viewport').getChildren()[i]; - var bbox = object.getBBox(); - - var newLocation = viewer.viewport.pixelFromPoint(annotationHandler.objectCenterPts[i]); - - if (object.tagName == "ellipse") { - - object.setAttribute("rx", (bbox.width/2)*scale); - object.setAttribute("ry", (bbox.height/2)*scale); - object.setAttribute("cx", newLocation.x); - object.setAttribute("cy", newLocation.y); - - } - else if (object.tagName == "rect") { - - object.setAttribute("width", (bbox.width)*scale); - object.setAttribute("height", (bbox.height)*scale); - object.setAttribute("x", newLocation.x-(bbox.width/2)*scale); - object.setAttribute("y", newLocation.y-(bbox.height/2)*scale); - - } - else { - - var points = String.split(object.getAttribute("points").trim(), ' '); - var newLocationRelPt = viewer.viewport.pointFromPixel(newLocation); - var distances = annotationHandler.originalCoords[i].distances; - var pointsStr = ""; - for (var j = 0; j < distances.length-1; j++) { - var pointPair = distances[j].plus(newLocationRelPt); - var pixelPoint = viewer.viewport.pixelFromPoint(pointPair); - pointsStr += pixelPoint.x + "," + pixelPoint.y + " "; - - } - object.setAttribute("points", pointsStr); - - } - var div = $$('div.annotcontainer')[i]; - div.style.left = newLocation.x-(bbox.width/2)*scale + "px"; - div.style.top = newLocation.y-(bbox.height/2)*scale + "px"; - div.style.width = (bbox.width)*scale + "px"; - div.style.height = (bbox.height)*scale + "px"; - - - } - - } - - annotationHandler.lastCenter = center; - zooming = false; - }; - - AnnotoolsOpenSeadragonHandler.prototype.handleMouseMove= function(evt) { - if(evt.preventDefault) - evt.preventDefault(); - - if (this.state == 'pan') { - //$('svg')[0].hide(); - $$('svg')[0].setStyle('opacity', 0); - var pixel = OpenSeadragon.getMousePosition(evt).minus - (OpenSeadragon.getElementPosition(viewer.element)); - var point = viewer.viewport.pointFromPixel(pixel); - } - - - }; - - AnnotoolsOpenSeadragonHandler.prototype.handleMouseUp= function(evt) { - - //if (evt.target.tagName.toLowerCase() == "button" || evt.target.tagName.toLowerCase() == "div") { - if (evt.target.tagName.toLowerCase() == "button") { - console.log("handleMouseUp: " + evt.target.tagName); return; - - } - if(evt.preventDefault) - evt.preventDefault(); - - if (this.state == 'pan') { - this.state = 'up'; - var pixel = - OpenSeadragon.getMousePosition(evt).minus - (OpenSeadragon.getElementPosition(viewer.element)); - - var diff = pixel.minus(this.stateOrigin); - - // handles a mouse click (zoom and pan to) - // otherwise we will handle the pan event - if (diff.x == 0 && diff.y == 0) { - - // setTimeout(function() { - //annotationHandler.handleZoomIn(); - $$('svg')[0].setStyle('opacity', 1); - // }, annotationHandler.animateWaitTime); - - } - else { - - $('originpt').setProperty('cx', - viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5,.5)).x); - $('originpt').setProperty('cy', - viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5,.5)).y); - - //$('svg')[0].show(); - $$('svg')[0].setStyle('opacity', 1); - for (var i = 0; i < $('viewport').getChildren().length; i++) { - - var object = $('viewport').getChildren()[i]; - //object.setAttribute("style", style="fill:none;stroke:lime;stroke-width:2"); - var bbox = object.getBBox(); - if (object.tagName == "ellipse") { - - var currX = bbox.x+bbox.width/2; - var currY = bbox.y+bbox.height/2; - object.setAttribute("cx", currX + diff.x); - object.setAttribute("cy", currY + diff.y); - - } - else if (object.tagName == "rect") { - - object.setAttribute("x", bbox.x + diff.x); - object.setAttribute("y", bbox.y + diff.y); - - } - else { - - var points = String.split(object.getAttribute("points").trim(), ' '); - var pointsStr = ""; - for (var j = 0; j < points.length; j++) { - var pointPair = String.split(points[j], ","); - pointsStr += (parseFloat(pointPair[0])+diff.x) + - "," + - (parseFloat(pointPair[1])+diff.y) + " "; - - - } - object.setAttribute("points", pointsStr); - + + } + if (evt.preventDefault) + evt.preventDefault(); + + if (this.state == 'pan') { + this.state = 'up'; + var pixel = + OpenSeadragon.getMousePosition(evt).minus + (OpenSeadragon.getElementPosition(viewer.element)); + + var diff = pixel.minus(this.stateOrigin); + + // handles a mouse click (zoom and pan to) + // otherwise we will handle the pan event + if (diff.x == 0 && diff.y == 0) { + + // setTimeout(function() { + //annotationHandler.handleZoomIn(); + if ($$('svg')[0]) { + $$('svg')[0].setStyle('opacity', 1) + } + // }, annotationHandler.animateWaitTime); + + } + else { + + $('originpt').setProperty('cx', + viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)).x); + $('originpt').setProperty('cy', + viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)).y); + + //$('svg')[0].show(); + if ($$('svg')[0]) { + $$('svg')[0].setStyle('opacity', 1) + } + + for (var i = 0; i < $('viewport').getChildren().length; i++) { + + var object = $('viewport').getChildren()[i]; + //object.setAttribute("style", style="fill:none;stroke:lime;stroke-width:2"); + var bbox = object.getBBox(); + if (object.tagName == "ellipse") { + + var currX = bbox.x + bbox.width / 2; + var currY = bbox.y + bbox.height / 2; + object.setAttribute("cx", currX + diff.x); + object.setAttribute("cy", currY + diff.y); + + } + else if (object.tagName == "rect") { + + object.setAttribute("x", bbox.x + diff.x); + object.setAttribute("y", bbox.y + diff.y); + + } + else { + + var points = String.split(object.getAttribute("points").trim(), ' '); + var pointsStr = ""; + for (var j = 0; j < points.length; j++) { + var pointPair = String.split(points[j], ","); + pointsStr += (parseFloat(pointPair[0]) + diff.x) + + "," + + (parseFloat(pointPair[1]) + diff.y) + " "; + + } + object.setAttribute("points", pointsStr); - var div = $$('div.annotcontainer')[i]; - - div.style.left = (bbox.x + diff.x) + "px"; - div.style.top = (bbox.y + diff.y)+ "px"; } - } + var div = $$('div.annotcontainer')[i]; + + div.style.left = (bbox.x + diff.x) + "px"; + div.style.top = (bbox.y + diff.y) + "px"; + } } - }; + } + +}; - AnnotoolsOpenSeadragonHandler.prototype.handleMouseDown= function(evt) { +AnnotoolsOpenSeadragonHandler.prototype.handleMouseDown = function (evt) { - if (evt.target.tagName.toLowerCase() == "button") { + if (evt.target.tagName.toLowerCase() == "button") { console.log("handleMouseDown: " + evt.target.tagName); return; - } - if(evt.preventDefault) - evt.preventDefault(); - this.state = 'pan'; - var pixel = OpenSeadragon.getMousePosition(evt).minus - (OpenSeadragon.getElementPosition(viewer.element)); - - $$('svg')[0].setStyle('opacity', 0); - this.stateOrigin = pixel; - - }; - - AnnotoolsOpenSeadragonHandler.prototype.handleMouseWheel= function(evt) { - if(evt.preventDefault) - evt.preventDefault(); - if((typeof($$('svg')[0]) != 'undefined') && ('setStyle' in $$('svg')[0])) - $$('svg')[0].setStyle('opacity', 0); - - if (this.annotool.mode == 'free_markup') - this.annotool.markSaveClick(null); - - if (evt.wheelDelta > 0) - this.viewer.viewport.zoomTo(this.viewer.viewport.getZoom()*1.2); - else - this.viewer.viewport.zoomTo(this.viewer.viewport.getZoom()/1.2); - }; - - AnnotoolsOpenSeadragonHandler.prototype.handleKeyPress= function(evt) { - delta = 48.0 / this.viewer.viewport.getZoom() * 0.005; - switch (evt.key) { + } + if (evt.preventDefault) + evt.preventDefault(); + this.state = 'pan'; + var pixel = OpenSeadragon.getMousePosition(evt).minus + (OpenSeadragon.getElementPosition(viewer.element)); + + if ($$('svg')[0]) { + //console.log("$$('svg')[0]", $$('svg')[0]); + $$('svg')[0].setStyle('opacity', 0); + } + + this.stateOrigin = pixel; + +}; + +AnnotoolsOpenSeadragonHandler.prototype.handleMouseWheel = function (evt) { + if (evt.preventDefault) + evt.preventDefault(); + if ((typeof($$('svg')[0]) != 'undefined') && ('setStyle' in $$('svg')[0])) + $$('svg')[0].setStyle('opacity', 0); + + if (this.annotool.mode == 'free_markup') + this.annotool.markSaveClick(null); + + if (evt.wheelDelta > 0) + this.viewer.viewport.zoomTo(this.viewer.viewport.getZoom() * 1.2); + else + this.viewer.viewport.zoomTo(this.viewer.viewport.getZoom() / 1.2); +}; + +AnnotoolsOpenSeadragonHandler.prototype.handleKeyPress = function (evt) { + delta = 48.0 / this.viewer.viewport.getZoom() * 0.005; + switch (evt.key) { case "a": - if (this.annotool.mode == 'free_markup') - { - this.annotool.markSaveClick(null); - } - delta_x = -delta; delta_y = 0; - var pt = this.viewer.viewport.getCenter(true).plus(new OpenSeadragon.Point(delta_x, delta_y)); - this.viewer.viewport.panTo(pt, false); - break; - - case "d": - if (this.annotool.mode == 'free_markup') - { - this.annotool.markSaveClick(null); - } - delta_x = delta; delta_y = 0; - var pt = this.viewer.viewport.getCenter(true).plus(new OpenSeadragon.Point(delta_x, delta_y)); - this.viewer.viewport.panTo(pt, false); - break; - - case "m": - this.annotool.lymheat = !this.annotool.lymheat; - this.annotool.getMultiAnnot(); - break; - - case "s": - if (this.annotool.mode == 'free_markup') - { - this.annotool.markSaveClick(null); - } - delta_x = 0; delta_y = delta; - var pt = this.viewer.viewport.getCenter(true).plus(new OpenSeadragon.Point(delta_x, delta_y)); - this.viewer.viewport.panTo(pt, false); - break; - - case "w": - if (this.annotool.mode == 'free_markup') - { - this.annotool.markSaveClick(null); - } - delta_x = 0; delta_y = -delta; - var pt = this.viewer.viewport.getCenter(true).plus(new OpenSeadragon.Point(delta_x, delta_y)); - this.viewer.viewport.panTo(pt, false); - break; - - case " ": annotool.toggleMarkups(); - break; - - case "1": - if (annotool.marking_choice == 'rb_Moving') { - document.getElementById('LymPos').checked = true; - annotool.drawMarkups(); - jQuery("canvas").css("cursor", "crosshair"); - jQuery("#drawRectangleButton").removeClass("active"); - jQuery("#drawDotButton").removeClass("active"); - jQuery("#drawFreelineButton").removeClass("active"); - annotool.marking_choice = 'LymPos'; - } else - document.getElementById('LymPos').checked = true; - break; + if (this.annotool.mode == 'free_markup') { + this.annotool.markSaveClick(null); + } + delta_x = -delta; + delta_y = 0; + var pt = this.viewer.viewport.getCenter(true).plus(new OpenSeadragon.Point(delta_x, delta_y)); + this.viewer.viewport.panTo(pt, false); + break; + + case "d": + if (this.annotool.mode == 'free_markup') { + this.annotool.markSaveClick(null); + } + delta_x = delta; + delta_y = 0; + var pt = this.viewer.viewport.getCenter(true).plus(new OpenSeadragon.Point(delta_x, delta_y)); + this.viewer.viewport.panTo(pt, false); + break; + + case "m": + this.annotool.lymheat = !this.annotool.lymheat; + this.annotool.getMultiAnnot(); + break; + + case "s": + if (this.annotool.mode == 'free_markup') { + this.annotool.markSaveClick(null); + } + delta_x = 0; + delta_y = delta; + var pt = this.viewer.viewport.getCenter(true).plus(new OpenSeadragon.Point(delta_x, delta_y)); + this.viewer.viewport.panTo(pt, false); + break; + + case "w": + if (this.annotool.mode == 'free_markup') { + this.annotool.markSaveClick(null); + } + delta_x = 0; + delta_y = -delta; + var pt = this.viewer.viewport.getCenter(true).plus(new OpenSeadragon.Point(delta_x, delta_y)); + this.viewer.viewport.panTo(pt, false); + break; + + case " ": + annotool.toggleMarkups(); + break; + + case "1": + if (annotool.marking_choice == 'rb_Moving') { + document.getElementById('LymPos').checked = true; + annotool.drawMarkups(); + jQuery("canvas").css("cursor", "crosshair"); + jQuery("#drawRectangleButton").removeClass("active"); + jQuery("#drawDotButton").removeClass("active"); + jQuery("#drawFreelineButton").removeClass("active"); + annotool.marking_choice = 'LymPos'; + } else + document.getElementById('LymPos').checked = true; + break; case "2": - if (annotool.marking_choice == 'rb_Moving') { - document.getElementById('LymNeg').checked = true; - annotool.drawMarkups(); - jQuery("canvas").css("cursor", "crosshair"); - jQuery("#drawRectangleButton").removeClass("active"); - jQuery("#drawDotButton").removeClass("active"); - jQuery("#drawFreelineButton").removeClass("active"); - annotool.marking_choice = 'LymNeg'; - } else - document.getElementById('LymNeg').checked = true; - break; + if (annotool.marking_choice == 'rb_Moving') { + document.getElementById('LymNeg').checked = true; + annotool.drawMarkups(); + jQuery("canvas").css("cursor", "crosshair"); + jQuery("#drawRectangleButton").removeClass("active"); + jQuery("#drawDotButton").removeClass("active"); + jQuery("#drawFreelineButton").removeClass("active"); + annotool.marking_choice = 'LymNeg'; + } else + document.getElementById('LymNeg').checked = true; + break; case "3": - if (annotool.marking_choice == 'rb_Moving') { - document.getElementById('LymPosBig').checked = true; - annotool.drawMarkups(); - jQuery("canvas").css("cursor", "crosshair"); - jQuery("#drawRectangleButton").removeClass("active"); - jQuery("#drawDotButton").removeClass("active"); - jQuery("#drawFreelineButton").removeClass("active"); - annotool.marking_choice = 'LymPosBig'; - } else - document.getElementById('LymPosBig').checked = true; - break; + if (annotool.marking_choice == 'rb_Moving') { + document.getElementById('LymPosBig').checked = true; + annotool.drawMarkups(); + jQuery("canvas").css("cursor", "crosshair"); + jQuery("#drawRectangleButton").removeClass("active"); + jQuery("#drawDotButton").removeClass("active"); + jQuery("#drawFreelineButton").removeClass("active"); + annotool.marking_choice = 'LymPosBig'; + } else + document.getElementById('LymPosBig').checked = true; + break; case "4": - if (annotool.marking_choice == 'rb_Moving') { - document.getElementById('LymNegBig').checked = true; - annotool.drawMarkups(); - jQuery("canvas").css("cursor", "crosshair"); - jQuery("#drawRectangleButton").removeClass("active"); - jQuery("#drawDotButton").removeClass("active"); - jQuery("#drawFreelineButton").removeClass("active"); - annotool.marking_choice = 'LymNegBig'; - } else - document.getElementById('LymNegBig').checked = true; - break; + if (annotool.marking_choice == 'rb_Moving') { + document.getElementById('LymNegBig').checked = true; + annotool.drawMarkups(); + jQuery("canvas").css("cursor", "crosshair"); + jQuery("#drawRectangleButton").removeClass("active"); + jQuery("#drawDotButton").removeClass("active"); + jQuery("#drawFreelineButton").removeClass("active"); + annotool.marking_choice = 'LymNegBig'; + } else + document.getElementById('LymNegBig').checked = true; + break; case "5": - if (annotool.marking_choice == 'rb_Moving') { - document.getElementById('TumorPos').checked = true; - annotool.drawMarkups(); - jQuery("canvas").css("cursor", "crosshair"); - jQuery("#drawRectangleButton").removeClass("active"); - jQuery("#drawDotButton").removeClass("active"); - jQuery("#drawFreelineButton").removeClass("active"); - annotool.marking_choice = 'TumorPos'; - } else - document.getElementById('TumorPos').checked = true; - break; + if (annotool.marking_choice == 'rb_Moving') { + document.getElementById('TumorPos').checked = true; + annotool.drawMarkups(); + jQuery("canvas").css("cursor", "crosshair"); + jQuery("#drawRectangleButton").removeClass("active"); + jQuery("#drawDotButton").removeClass("active"); + jQuery("#drawFreelineButton").removeClass("active"); + annotool.marking_choice = 'TumorPos'; + } else + document.getElementById('TumorPos').checked = true; + break; case "6": - if (annotool.marking_choice == 'rb_Moving') { - document.getElementById('TumorNeg').checked = true; - annotool.drawMarkups(); - jQuery("canvas").css("cursor", "crosshair"); - jQuery("#drawRectangleButton").removeClass("active"); - jQuery("#drawDotButton").removeClass("active"); - jQuery("#drawFreelineButton").removeClass("active"); - annotool.marking_choice = 'TumorNeg'; - } else - document.getElementById('TumorNeg').checked = true; - break; - - case "7": document.getElementById('rb_Moving').checked = true; - var mock_evt = {target:{id:'rb_Moving'}}; - annotool.radiobuttonChange(mock_evt); - break; - - case "q": annotool.revertWeight(null); - break; - } - }; + if (annotool.marking_choice == 'rb_Moving') { + document.getElementById('TumorNeg').checked = true; + annotool.drawMarkups(); + jQuery("canvas").css("cursor", "crosshair"); + jQuery("#drawRectangleButton").removeClass("active"); + jQuery("#drawDotButton").removeClass("active"); + jQuery("#drawFreelineButton").removeClass("active"); + annotool.marking_choice = 'TumorNeg'; + } else + document.getElementById('TumorNeg').checked = true; + break; + + case "7": + document.getElementById('rb_Moving').checked = true; + var mock_evt = {target: {id: 'rb_Moving'}}; + annotool.radiobuttonChange(mock_evt); + break; + + case "q": + annotool.revertWeight(null); + break; + } +}; diff --git a/js/annotationtoolslymph/geoJSONHandler_Lymph.js b/js/annotationtoolslymph/geoJSONHandler_Lymph.js index 39f673d47..830f8d3da 100644 --- a/js/annotationtoolslymph/geoJSONHandler_Lymph.js +++ b/js/annotationtoolslymph/geoJSONHandler_Lymph.js @@ -1,137 +1,132 @@ annotools.prototype.generateGeoTemplate = function () { - - var case_id = this.iid - var subject_id = case_id.substr(0,12); - if(subject_id.substr(0,4) != "TCGA"){ - //subject_id = ""; - } - - var geoJSONTemplate = { - 'type': 'Feature', - 'parent_id': 'self', - 'randval': Math.random(), - 'geometry': { - 'type': 'Polygon', - 'coordinates': [] - }, - 'normalized': true, - 'object_type': 'annotation', // nucleus? - 'properties': { - 'scalar_features': [], - 'annotations': [] - }, - 'footprint': 10000, - 'provenance': { - 'analysis': { - 'execution_id': 'humantest', - 'study_id': "", - 'source': "human", - 'computation': 'segmentation' - }, - 'image': { - 'case_id': case_id, - 'subject_id': subject_id - } - }, - 'date': Date.now() - } - return geoJSONTemplate -} -annotools.prototype.convertRectToGeo = function (annotation) { - + var case_id = this.iid; + var subject_id = case_id.substr(0, 12); + if (subject_id.substr(0, 4) != "TCGA") { + //subject_id = ""; + } - var origin = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(annotation.x), this.imagingHelper.physicalToDataY(annotation.y)) - var max = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(annotation.x + annotation.w), this.imagingHelper.physicalToDataY(annotation.y + annotation.h)) + var geoJSONTemplate = { + 'type': 'Feature', + 'parent_id': 'self', + 'randval': Math.random(), + 'geometry': { + 'type': 'Polygon', + 'coordinates': [] + }, + 'normalized': true, + 'object_type': 'annotation', // nucleus? + 'properties': { + 'scalar_features': [], + 'annotations': [] + }, + 'footprint': 10000, + 'provenance': { + 'analysis': { + 'execution_id': 'humantest', + 'study_id': "", + 'source': "human", + 'computation': 'segmentation' + }, + 'image': { + 'case_id': case_id, + 'subject_id': subject_id + } + }, + 'date': Date.now() + }; + return geoJSONTemplate +}; +annotools.prototype.convertRectToGeo = function (annotation) { + var origin = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(annotation.x), this.imagingHelper.physicalToDataY(annotation.y)); + var max = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(annotation.x + annotation.w), this.imagingHelper.physicalToDataY(annotation.y + annotation.h)); - /* Compute footprint(area)*/ - var physicalX1 = this.imagingHelper.logicalToPhysicalX(annotation.x); - var physicalY1 = this.imagingHelper.logicalToPhysicalY(annotation.y); - var physicalX2 = this.imagingHelper.logicalToPhysicalX(annotation.x + annotation.w); - var physicalY2 = this.imagingHelper.logicalToPhysicalY(annotation.y + annotation.h); + /* Compute footprint(area)*/ + var physicalX1 = this.imagingHelper.logicalToPhysicalX(annotation.x); + var physicalY1 = this.imagingHelper.logicalToPhysicalY(annotation.y); + var physicalX2 = this.imagingHelper.logicalToPhysicalX(annotation.x + annotation.w); + var physicalY2 = this.imagingHelper.logicalToPhysicalY(annotation.y + annotation.h); - var helper = this.imagingHelper; - var dataX1 = helper.physicalToDataX(physicalX1); - var dataY1 = helper.physicalToDataY(physicalY1); - var dataX2 = helper.physicalToDataX(physicalX2); - var dataY2 = helper.physicalToDataY(physicalY2); + var helper = this.imagingHelper; + var dataX1 = helper.physicalToDataX(physicalX1); + var dataY1 = helper.physicalToDataY(physicalY1); + var dataX2 = helper.physicalToDataX(physicalX2); + var dataY2 = helper.physicalToDataY(physicalY2); - var area = (dataX2 - dataX1)*(dataY2-dataY1); + var area = (dataX2 - dataX1) * (dataY2 - dataY1); - var coordinates = [] - var x = annotation.x - var y = annotation.y - var w = annotation.w - var h = annotation.h - var geoAnnot = this.generateGeoTemplate() - coordinates.push([]) - // coordinates[0].push([]) - coordinates[0].push([x, y]) - coordinates[0].push([x + w, y]) - coordinates[0].push([x + w, y + h]) - coordinates[0].push([x, y + h]) - geoAnnot.x = x - geoAnnot.y = y; - geoAnnot.footprint = area; - geoAnnot.geometry.coordinates = coordinates + var coordinates = []; + var x = annotation.x; + var y = annotation.y; + var w = annotation.w; + var h = annotation.h; + var geoAnnot = this.generateGeoTemplate(); + coordinates.push([]); + // coordinates[0].push([]) + coordinates[0].push([x, y]); + coordinates[0].push([x + w, y]); + coordinates[0].push([x + w, y + h]); + coordinates[0].push([x, y + h]); + geoAnnot.x = x; + geoAnnot.y = y; + geoAnnot.footprint = area; + geoAnnot.geometry.coordinates = coordinates; - return geoAnnot -} + return geoAnnot +}; annotools.prototype.convertPencilToGeo = function (annotation) { - var origin = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(annotation.x), this.imagingHelper.physicalToDataY(annotation.y)) - var max = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(annotation.x + annotation.w), this.imagingHelper.physicalToDataY(annotation.y + annotation.h)) - - /* Compute footprint(area)*/ - var physicalX1 = this.imagingHelper.logicalToPhysicalX(annotation.x); - var physicalY1 = this.imagingHelper.logicalToPhysicalY(annotation.y); - var physicalX2 = this.imagingHelper.logicalToPhysicalX(annotation.x + annotation.w); - var physicalY2 = this.imagingHelper.logicalToPhysicalY(annotation.y + annotation.h); - - var helper = this.imagingHelper; - var dataX1 = helper.physicalToDataX(physicalX1); - var dataY1 = helper.physicalToDataY(physicalY1); - var dataX2 = helper.physicalToDataX(physicalX2); - var dataY2 = helper.physicalToDataY(physicalY2); - - - var area = Math.abs((dataX2 - dataX1))*Math.abs((dataY2-dataY1)); - - - - - var points = annotation.points - var p = points.split(' ') - var geocoords = [] - - for (var i = 0; i < p.length; i++) { - var pt = p[i].split(',') - var ptx = +pt[0] - var pty = +pt[1] - geocoords.push([ptx, pty]) - } - - var geojson = this.generateGeoTemplate() - var coordinates = [] - coordinates.push([]) - geojson.geometry = {} - geojson.geometry.coordinates = [geocoords] - geojson.footprint = area; - // set x, y and width and height - geojson.x = annotation.x - geojson.y = annotation.y - // geojson.w = annotation.w - // geojson.h = annotation.h - - // console.log(geojson) - return geojson -} + var origin = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(annotation.x), this.imagingHelper.physicalToDataY(annotation.y)); + var max = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(annotation.x + annotation.w), this.imagingHelper.physicalToDataY(annotation.y + annotation.h)); + + /* Compute footprint(area)*/ + var physicalX1 = this.imagingHelper.logicalToPhysicalX(annotation.x); + var physicalY1 = this.imagingHelper.logicalToPhysicalY(annotation.y); + var physicalX2 = this.imagingHelper.logicalToPhysicalX(annotation.x + annotation.w); + var physicalY2 = this.imagingHelper.logicalToPhysicalY(annotation.y + annotation.h); + + var helper = this.imagingHelper; + var dataX1 = helper.physicalToDataX(physicalX1); + var dataY1 = helper.physicalToDataY(physicalY1); + var dataX2 = helper.physicalToDataX(physicalX2); + var dataY2 = helper.physicalToDataY(physicalY2); + + + var area = Math.abs((dataX2 - dataX1)) * Math.abs((dataY2 - dataY1)); + + + var points = annotation.points; + var p = points.split(' '); + var geocoords = []; + + for (var i = 0; i < p.length; i++) { + var pt = p[i].split(','); + var ptx = +pt[0]; + var pty = +pt[1]; + geocoords.push([ptx, pty]) + } + + var geojson = this.generateGeoTemplate(); + var coordinates = []; + coordinates.push([]); + geojson.geometry = {}; + geojson.geometry.coordinates = [geocoords]; + geojson.footprint = area; + // set x, y and width and height + geojson.x = annotation.x; + geojson.y = annotation.y; + // geojson.w = annotation.w + // geojson.h = annotation.h + + // console.log(geojson) + return geojson +}; /* var convertGeo = function(points){ @@ -155,9 +150,9 @@ annotools.prototype.convertAnnotationsToGeoJSON = function() { geoJSONs = [] var annotations = this.annotations - + for(var i in annotations) { - + var annotation = annotations[i] //console.log(annotation) @@ -165,8 +160,8 @@ annotools.prototype.convertAnnotationsToGeoJSON = function() { if(points) { //is a polygon //console.log(points) geo = convertGeo(points) - geoJSONs.push(geo); - + geoJSONs.push(geo); + } } //console.log(geoJSONs) @@ -175,72 +170,72 @@ annotools.prototype.convertAnnotationsToGeoJSON = function() { } */ -function endProfile (startTime) { - // nvar t2 = performance.now() - // console.log(startTime) - // console.log(t2) - // console.log("Total time: "+ (t2-startTime)) +function endProfile(startTime) { + // nvar t2 = performance.now() + // console.log(startTime) + // console.log(t2) + // console.log("Total time: "+ (t2-startTime)) } annotools.prototype.generateCanvas = function (annotations) { - // console.log(annotation) - // var annotation = annotations[ii] - //var intersect_label = this.calculateIntersect(); - var annotations = this.annotations - if (annotations) { - var markup_svg = document.getElementById('markups') - if (markup_svg) { - // console.log("destroying") - markup_svg.destroy() - } - // console.log(annotations.length) - // console.log(this.canvas) - var container = document.getElementsByClassName(this.canvas)[0].childNodes[0] // Get The Canvas Container - // console.log(container) - var context = container.getContext('2d') - context.fillStyle = '#f00' - // console.log(nativepoints) - // var container = document.getElementsByClassName(this.cavas)[0] - // console.log(container) - var width = parseInt(container.offsetWidth) - var height = parseInt(container.offsetHeight) - /* Why is there an ellipse in the center? */ - /* - var svgHtml = '' - svgHtml += '' - svgHtml += '' - var origin = viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5,.5)) - svgHtml += '' - svgHtml += '' - svgHtml += '' - */ - for (var i = 0; i < annotations.length; i++) { - var annotation = annotations[i] - var nativepoints = annotation.geometry.coordinates[0] - - var offset = OpenSeadragon.getElementOffset(viewer.canvas) - // svgHtml += ' 2) { - context.beginPath() - var x0 = this.imagingHelper.logicalToPhysicalX(nativepoints[0][0]) - var x1 = this.imagingHelper.logicalToPhysicalY(nativepoints[0][1]) - context.moveTo(x0, x1) - } - for (var k = 1; k < nativepoints.length; k++) { - var px = this.imagingHelper.logicalToPhysicalX(nativepoints[k][0]) - var py = this.imagingHelper.logicalToPhysicalY(nativepoints[k][1]) + // console.log(annotation) + // var annotation = annotations[ii] + //var intersect_label = this.calculateIntersect(); + var annotations = this.annotations; + if (annotations) { + var markup_svg = document.getElementById('markups'); + if (markup_svg) { + // console.log("destroying") + markup_svg.destroy() + } + // console.log(annotations.length) + // console.log(this.canvas) + var container = document.getElementsByClassName(this.canvas)[0].childNodes[0]; // Get The Canvas Container + // console.log(container) + var context = container.getContext('2d'); + context.fillStyle = '#f00'; + // console.log(nativepoints) + // var container = document.getElementsByClassName(this.cavas)[0] + // console.log(container) + var width = parseInt(container.offsetWidth); + var height = parseInt(container.offsetHeight); + /* Why is there an ellipse in the center? */ + /* + var svgHtml = '' + svgHtml += '' + svgHtml += '' + var origin = viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5,.5)) + svgHtml += '' + svgHtml += '' + svgHtml += '' + */ + for (var i = 0; i < annotations.length; i++) { + var annotation = annotations[i]; + var nativepoints = annotation.geometry.coordinates[0]; + + var offset = OpenSeadragon.getElementOffset(viewer.canvas); + // svgHtml += ' 2) { + context.beginPath(); + var x0 = this.imagingHelper.logicalToPhysicalX(nativepoints[0][0]); + var x1 = this.imagingHelper.logicalToPhysicalY(nativepoints[0][1]); + context.moveTo(x0, x1) + } + for (var k = 1; k < nativepoints.length; k++) { + var px = this.imagingHelper.logicalToPhysicalX(nativepoints[k][0]); + var py = this.imagingHelper.logicalToPhysicalY(nativepoints[k][1]); - context.lineTo(px, py) - } - context.strokeStyle = 'blue' - context.stokeWidth = 6 - context.closePath() - context.stroke() + context.lineTo(px, py) + } + context.strokeStyle = 'blue'; + context.stokeWidth = 6; + context.closePath(); + context.stroke() + } } - } -} +}; /* var clickSVG = function(evt, annotation){ //var a = annotation @@ -251,423 +246,577 @@ var clickSVG = function(evt, annotation){ */ annotools.prototype.generateSVG = function (annotations) { - // console.log(annotation) - // var annotation = annotations[ii] - //var intersect_label = this.calculateIntersect(); - //console.log(this.heat_weight); - var self =this; - var annotations = this.annotations - if (annotations) { - var markup_svg = document.getElementById('markups') - if (markup_svg) { - // console.log("destroying") - markup_svg.destroy() - } - - // console.log(annotations.length) - var container = document.getElementsByClassName(this.canvas)[0] // Get The Canvas Container - // console.log(nativepoints) - // var container = document.getElementsByClassName(this.cavas)[0] - // console.log(container) - var width = parseInt(container.offsetWidth) - var height = parseInt(container.offsetHeight) - /* Why is there an ellipse in the center? */ - var svgHtml = '' - svgHtml += '' - svgHtml += '' - var origin = viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)) - svgHtml += '' - svgHtml += '' - svgHtml += '' - - highres = false; - for (var i = 0; i < annotations.length; i++) { - if (annotations[i].footprint < 100000) - { - highres = true; - break; + // console.log(annotation) + // var annotation = annotations[ii] + //var intersect_label = this.calculateIntersect(); + //console.log(this.heat_weight); + var self = this; + var annotations = this.annotations; + if (annotations) { + var markup_svg = document.getElementById('markups'); + if (markup_svg) { + // console.log("destroying") + markup_svg.destroy() } - } - if (this.imagingHelper._viewportWidth * this.imagingHelper._viewportHeight > 0.06) + // console.log(annotations.length) + var container = document.getElementsByClassName(this.canvas)[0]; // Get The Canvas Container + // console.log(nativepoints) + // var container = document.getElementsByClassName(this.cavas)[0] + // console.log(container) + var width = parseInt(container.offsetWidth); + var height = parseInt(container.offsetHeight); + /* Why is there an ellipse in the center? */ + var svgHtml = ''; + svgHtml += ''; + svgHtml += ''; + var origin = viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(.5, .5)); + svgHtml += ''; + svgHtml += ''; + svgHtml += ''; + highres = false; + for (var i = 0; i < annotations.length; i++) { + if (annotations[i].footprint < 100000 || appid == "qualheat") { + highres = true; + break; + } + } - smth_or_not = highres; - if (smth_or_not) { - smoothed_anno = this.heatmap_smoothing(1, 0.01 + 2 * Math.pow(this.heat_weight[2], 2)); - } + if (this.imagingHelper._viewportWidth * this.imagingHelper._viewportHeight > 0.06 && appid != "qualheat") + highres = false; - var intersect_label = this.calculateIntersect(highres); + smth_or_not = highres; + if (smth_or_not) { + smoothed_anno = this.heatmap_smoothing(1, 0.01 + 2 * Math.pow(this.heat_weight[2], 2)); + } - for (var i = 0; i < annotations.length; i++) { - if (smth_or_not) - var smoothed = smoothed_anno[i] - var annotation = annotations[i] - if (((highres == false) && (annotation.footprint <= 100000)) || ((highres == true) && (annotation.footprint > 100000))) - if (annotation.object_type == 'heatmap_multiple') - continue; + var intersect_label = this.calculateIntersect(highres); - if (annotation.object_type == 'marking') - { - if (annotation.properties.annotations.mark_type == 'LymPos' || annotation.properties.annotations.mark_type == 'LymNeg') - { - //continue; - } + for (var i = 0; i < annotations.length; i++) { + if (smth_or_not) + var smoothed = smoothed_anno[i]; + var annotation = annotations[i]; + if (((highres == false) && (annotation.footprint <= 100000)) || ((highres == true) && (annotation.footprint > 100000))) + if (annotation.object_type == 'heatmap_multiple') + continue; - if (annotation.properties.annotations.username != this.username) - continue; - } - - if (this.lymheat == false) - { - if ((annotation.object_type == 'marking') && (annotation.properties.annotations.mark_type == 'LymPos' || annotation.properties.annotations.mark_type == 'LymNeg')) - { - continue; - } - if (annotation.object_type == 'heatmap' || annotation.object_type == 'heatmap_multiple') - { - continue; - } - } + if (annotation.object_type == 'marking') { + if (annotation.properties.annotations.mark_type == 'LymPos' || annotation.properties.annotations.mark_type == 'LymNeg' || + annotation.properties.annotations.mark_type == 'AlgoA' || annotation.properties.annotations.mark_type == 'AlgoB') { + //continue; + } - var id = ''; - - if (annotation['_id']) - id = annotation['_id']['$oid'] - // console.log(annotation) - var nativepoints = annotation.geometry.coordinates[0] - - // var offset = OpenSeadragon.getElementOffset(viewer.canvas) - var algorithm_id = annotation.provenance.analysis.execution_id - var color = algorithm_color[algorithm_id] - - // var svg = - //svgHtml += '' - if(color === undefined) - color = 'lime' - //svgHtml += '" style="fill:transparent; stroke:'+color+ '; stroke-width:2.5"/>' - //svgHtml += '" style="fill:' + '#feedde' + ';fill-opacity: 0.6;stroke-width:0"/>'; - //console.log(this.heatmap_opacity); - //console.log(this.imagingHelper._viewportWidth); - switch (annotation.object_type) - { - case 'heatmap': - //console.log('case heatmap'); - //var heatmapIndex = parseInt(parseInt((annotation.properties.metric_value * 10))/2.5); - var heatmapIndex = parseInt(parseInt(((1-annotation.properties.metric_value) * 10))/2.5); - var heatcolor = this.heatmapColor[heatmapIndex]; - svgHtml += '" style="fill:' + heatcolor.toString() + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; - break; - case 'heatmap_multiple': - if (smth_or_not) { - var lym_score = smoothed; - } else { - var lym_score = annotation.properties.multiheat_param.metric_array[0]; + if (this.lymheat == false) { + if ((annotation.object_type == 'marking') && (annotation.properties.annotations.mark_type == 'LymPos' || annotation.properties.annotations.mark_type == 'LymNeg' || + annotation.properties.annotations.mark_type == 'AlgoA' || annotation.properties.annotations.mark_type == 'AlgoB')) { + continue; + } + if (annotation.object_type == 'heatmap' || annotation.object_type == 'heatmap_multiple') { + continue; + } + } + + var id = ''; + + if (annotation['_id']) + id = annotation['_id']['$oid']; + // console.log(annotation) + var nativepoints = annotation.geometry.coordinates[0]; + + // var offset = OpenSeadragon.getElementOffset(viewer.canvas) + var algorithm_id = annotation.provenance.analysis.execution_id; + var color = algorithm_color[algorithm_id]; + + // var svg = + //svgHtml += '' + if (color === undefined) + color = 'lime'; + //svgHtml += '" style="fill:transparent; stroke:'+color+ '; stroke-width:2.5"/>' + //svgHtml += '" style="fill:' + '#feedde' + ';fill-opacity: 0.6;stroke-width:0"/>'; + //console.log(this.heatmap_opacity); + //console.log(this.imagingHelper._viewportWidth); + switch (annotation.object_type) { + case 'heatmap': + //console.log('case heatmap'); + //var heatmapIndex = parseInt(parseInt((annotation.properties.metric_value * 10))/2.5); + var heatmapIndex = parseInt(parseInt(((1 - annotation.properties.metric_value) * 10)) / 2.5); + var heatcolor = this.heatmapColor[heatmapIndex]; + svgHtml += '" style="fill:' + heatcolor.toString() + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; + break; + case 'heatmap_multiple': + //console.log(annotation.properties.metric_value); + if (smth_or_not) { + var lym_score = smoothed; + } else { + var lym_score = annotation.properties.multiheat_param.metric_array[0]; + } + var nec_score = annotation.properties.multiheat_param.metric_array[1]; + var nec_weight = this.heat_weight[1]; + var lym_weight = 1 - this.heat_weight[0]; + + var lym_color_index = lym_score >= lym_weight ? 2 : 0; + var nec_color_index = nec_score >= nec_weight ? 1 : 0; + var lym_checked = document.getElementById('cb1').checked; + var nec_checked = document.getElementById('cb2').checked; + + // Added for temp weight boxes + lym_checked = (document.getElementById('LymSe').checked || document.getElementById('BothSe').checked); + nec_checked = (document.getElementById('NecSe').checked || document.getElementById('BothSe').checked); + + + selected_heatmap = this.heatmapColor[0]; + selected_opacity = this.heatmap_opacity; + //console.log(intersect_label); + if (intersect_label[i] != 0) { + //console.log("In inteersection"); + switch (intersect_label[i].label) { + case -1: + svgHtml += '" style="fill:' + this.heatmapColor[4] + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; + break; + case 1: + svgHtml += '" style="fill:' + this.heatmapColor[3] + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; + break; + } + } + else { + //console.log("In heatmap loop"); + if (lym_checked == true && nec_checked == false) { + selected_heatmap = this.heatmapColor[lym_color_index]; + //svgHtml += '" style="fill:' + this.heatmapColor[lym_color_index] + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; + } + + if (lym_checked == false && nec_checked == true) { + selected_heatmap = this.heatmapColor[nec_color_index]; + //svgHtml += '" style="fill:' + this.heatmapColor[nec_color_index] + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; + } + + if (lym_checked == true && nec_checked == true) { + selected_heatmap = this.heatmapColor[lym_color_index * (1 - nec_color_index)]; + //svgHtml += '" style="fill:' + this.heatmapColor[lym_color_index*(1-nec_color_index)] + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; + } + + if (lym_checked == false && nec_checked == false) { + selected_heatmap = this.heatmapColor[0]; + //svgHtml += '" style="fill:' + this.heatmapColor[0] + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; + } + } + + if (selected_heatmap == this.heatmapColor[0]) { + selected_opacity = 0.2; + } + + svgHtml += '" style="fill:' + selected_heatmap + ';fill-opacity: ' + selected_opacity + ';stroke-width:0"/>'; + //console.log(selected_heatmap); + //console.log(lym_checked == true && nec_checked == true); +/* + var combo = lym_score; + if (nec_score >= (1-this.heat_weight1)) + { + combo = 0; + } + var heatmapIndex = parseInt(parseInt((combo * 10))/2.5); + var heatcolor = this.heatmapColor[heatmapIndex]; + svgHtml += '" style="fill:' + heatcolor.toString() + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; + */ + break; + case 'heatmap_quality': + var quality_value = annotation.properties.metric_value; + var lower_threshold = window.qualthresholds.low / 100; + var upper_threshold = window.qualthresholds.high / 100; + var median = window.qualthresholds.median / 100; + var self = this; + selected_heatmap = this.heatmapColorQuality[2]; + selected_opacity = this.heatmap_opacity; + SELECTED_ALGORITHM_LIST = SELECTED_ALGORITHM_LIST.sort(); + + algorithms = SELECTED_ALGORITHM_LIST; + console.log(intersect_label[i].label); + + if (intersect_label[i].label != 0 && !(typeof intersect_label[i].label === "undefined")) { + if (appid == "qualheat") { + this.oneExecIDChosenFiltered(algorithms, "quality_", "Select only one 'quality' algorithm.", function (qeid) { + if (qeid == intersect_label[i].eid) { + switch (intersect_label[i].label) { + case -1: + selected_heatmap = self.heatmapColorQuality[0]; + break; + case 1: + selected_heatmap = self.heatmapColorQuality[4]; + break; + } + } + else { + if (quality_value <= lower_threshold) { + selected_heatmap = self.heatmapColorQuality[0]; + } + + if (quality_value > lower_threshold && quality_value <= (median - 0.05)) { + selected_heatmap = self.heatmapColorQuality[1]; + } + + if (quality_value >= upper_threshold) { + selected_heatmap = self.heatmapColorQuality[4]; + } + + if (quality_value < upper_threshold && quality_value >= (median + 0.05)) { + selected_heatmap = self.heatmapColorQuality[3]; + } + + if (quality_value < 0) { + selected_heatmap = self.heatmapColorQuality[2]; + selected_opacity = 0.2 + } + } + }); + } + } + else { + if (quality_value <= lower_threshold) { + selected_heatmap = this.heatmapColorQuality[0]; + } + + if (quality_value > lower_threshold && quality_value <= (median - 0.05)) { + selected_heatmap = this.heatmapColorQuality[1]; + } + + if (quality_value >= upper_threshold) { + selected_heatmap = this.heatmapColorQuality[4]; + } + + if (quality_value < upper_threshold && quality_value >= (median + 0.05)) { + selected_heatmap = this.heatmapColorQuality[3]; + } + + if (quality_value < 0) { + selected_heatmap = this.heatmapColorQuality[2]; + selected_opacity = 0.2 + } + } + svgHtml += '" style="fill:' + selected_heatmap + ';fill-opacity: ' + selected_opacity + ';stroke-width:0"/>'; + break; + case 'marking': + var line_color = ''; + var stroke_width = 2.5; + var stroke_opacity = 1; +// console.log(annotation); + switch (annotation.properties.annotations.mark_type) { + case 'LymPos': + line_color = 'red'; + stroke_width = 2.5 * annotation.properties.annotations.mark_width; + break; + case 'LymNeg': + line_color = 'blue'; + stroke_width = 2.5 * annotation.properties.annotations.mark_width; + break; + case 'TumorPos': + line_color = 'orange'; + break; + case 'TumorNeg': + line_color = 'lime'; + break; + case 'AlgoA': + line_color = 'red'; + stroke_width = 2.5 * annotation.properties.annotations.mark_width; + break; + case 'AlgoB': + line_color = 'blue'; + stroke_width = 2.5 * annotation.properties.annotations.mark_width; + break; + case 'AlgoAP': + line_color = 'orange'; + break; + case 'AlgoBP': + line_color = 'lime'; + break; + default: + line_color = jQuery("#" + annotation.properties.annotations.mark_type).attr("color"); + if (jQuery("#" + annotation.properties.annotations.mark_type + '_visualized').is(":checked")) { + stroke_opacity = 1; + } + break; + } + //svgHtml += '" style="fill:transparent; stroke:'+line_color+ '; stroke-width:2.5"/>' + if (appid == "qualheat") { + this.oneExecIDChosenFiltered(algorithms, "quality_", "Select only one 'quality' algorithm.", function (qeid) { + if (qeid == annotation.properties.annotations.mark_eid) { + svgHtml += '" style="fill:transparent; stroke:' + line_color + '; stroke-width:' + stroke_width + '"/>'; + } + }); + } else { + //svgHtml += '" style="fill:transparent; stroke:'+line_color+ '; stroke-width:' + stroke_width + '"/>'; + svgHtml += '" style="fill:transparent; stroke:' + line_color + '; stroke-width:' + stroke_width + '; stroke-opacity:' + stroke_opacity + '"/>'; + } + break; + default: + svgHtml += '" style="fill:transparent; stroke:' + color + '; stroke-width:2.5"/>' + } + /* + if (annotation.object_type === 'heatmap') + { + var heatmapIndex = parseInt(parseInt((annotation.properties.metric_value * 10))/2.5); + var heatcolor = this.heatmapColor[heatmapIndex]; + svgHtml += '" style="fill:' + heatcolor.toString() + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; + } + else + { + svgHtml += '" style="fill:transparent; stroke:'+color+ '; stroke-width:2.5"/>' + } + */ } - var nec_score = annotation.properties.multiheat_param.metric_array[1]; - var nec_weight = this.heat_weight[1]; - var lym_weight = 1-this.heat_weight[0]; - - var lym_color_index = lym_score >= lym_weight ? 2 : 0; - var nec_color_index = nec_score >= nec_weight ? 1 : 0; - var lym_checked = document.getElementById('cb1').checked; - var nec_checked = document.getElementById('cb2').checked; - - // Added for temp weight boxes - lym_checked = (document.getElementById('LymSe').checked || document.getElementById('BothSe').checked); - nec_checked = (document.getElementById('NecSe').checked || document.getElementById('BothSe').checked); - - - selected_heatmap = this.heatmapColor[0]; - selected_opacity = this.heatmap_opacity; - - if (intersect_label[i] != 0) - { - switch (intersect_label[i]) - { - case -1: svgHtml += '" style="fill:' + this.heatmapColor[4] + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; break; - case 1: svgHtml += '" style="fill:' + this.heatmapColor[3] + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; break; - } - } - else - { - if (lym_checked == true && nec_checked == false) - { - selected_heatmap = this.heatmapColor[lym_color_index]; - //svgHtml += '" style="fill:' + this.heatmapColor[lym_color_index] + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; - } - - if (lym_checked == false && nec_checked == true) - { - selected_heatmap = this.heatmapColor[nec_color_index]; - //svgHtml += '" style="fill:' + this.heatmapColor[nec_color_index] + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; - } - - if (lym_checked == true && nec_checked == true) - { - selected_heatmap = this.heatmapColor[lym_color_index*(1-nec_color_index)]; - //svgHtml += '" style="fill:' + this.heatmapColor[lym_color_index*(1-nec_color_index)] + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; - } - - if (lym_checked == false && nec_checked == false) - { - selected_heatmap = this.heatmapColor[0]; - //svgHtml += '" style="fill:' + this.heatmapColor[0] + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; - } - } - - if (selected_heatmap == this.heatmapColor[0]) - { - selected_opacity = 0.2; - } - - svgHtml += '" style="fill:' + selected_heatmap + ';fill-opacity: ' + selected_opacity + ';stroke-width:0"/>'; - /* - var combo = lym_score; - if (nec_score >= (1-this.heat_weight1)) - { - combo = 0; - } - var heatmapIndex = parseInt(parseInt((combo * 10))/2.5); - var heatcolor = this.heatmapColor[heatmapIndex]; - svgHtml += '" style="fill:' + heatcolor.toString() + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; - */ - break; - - case 'marking': - var line_color = ''; - var stroke_width = 2.5; - switch (annotation.properties.annotations.mark_type) - { - case 'LymPos': line_color = 'red'; stroke_width = 2.5*annotation.properties.annotations.mark_width; break; - case 'LymNeg': line_color = 'blue'; stroke_width = 2.5*annotation.properties.annotations.mark_width; break; - case 'TumorPos': line_color = 'orange'; break; - case 'TumorNeg': line_color = 'lime'; break; - } - //svgHtml += '" style="fill:transparent; stroke:'+line_color+ '; stroke-width:2.5"/>' - svgHtml += '" style="fill:transparent; stroke:'+line_color+ '; stroke-width:' + stroke_width + '"/>'; - break; - default: - svgHtml += '" style="fill:transparent; stroke:'+color+ '; stroke-width:2.5"/>' - } - /* - if (annotation.object_type === 'heatmap') - { - var heatmapIndex = parseInt(parseInt((annotation.properties.metric_value * 10))/2.5); - var heatcolor = this.heatmapColor[heatmapIndex]; - svgHtml += '" style="fill:' + heatcolor.toString() + ';fill-opacity: ' + this.heatmap_opacity + ';stroke-width:0"/>'; - } - else - { - svgHtml += '" style="fill:transparent; stroke:'+color+ '; stroke-width:2.5"/>' - } - */ - } - //Debug - //console.log(svgHtml); - this.svg = new Element('div', { - styles: { - position: 'absolute', - left: 0, - top: 0, - width: '100%', - height: '100%' - }, - html: svgHtml - }).inject(container) - } + //Debug + //console.log(svgHtml); + + this.svg = new Element('div', { + styles: { + position: 'absolute', + left: 0, + top: 0, + width: '100%', + height: '100%' + }, + html: svgHtml + }).inject(container) + } + var ctrl = false; + var alt = false; + // Use CTRL & Windows key (command key on Mac) + jQuery(document).keydown(function (event) { + if (event.which === 17 || event.which === 91) + { + //Ctrl key and left window key + console.log(event.which); + ctrl = true; + } + else if (event.which === 18 || event.which === 92) + { + //Alt key and right window key + console.log(event.which); + alt = true; + } + //console.log("ctrl: " + ctrl + ", alt: " + alt); - var ctrl = false; - jQuery(document).keydown(function(event){ - //console.log("control"); - //console.log(event); - if(event.which == 17 || event.which == 91) - ctrl = true; + }); - }); - jQuery(document).keyup(function(){ + jQuery(document).keyup(function () { ctrl = false; - }); - jQuery('.annotationsvg').mousedown(function (event) { + alt = false; + }); + + //jQuery(".annotationsvg").mousedown(function (event) { + jQuery(".annotationsvg").click(function (event) { //console.log(event.which); - if(ctrl){ - //console.log("double clicked"); - event.preventDefault(); - event.stopPropagation(); - event.stopImmediatePropagation(); - //return false; - } else { - return; + if (ctrl) { + //console.log("double clicked"); + event.preventDefault(); + event.stopPropagation(); + event.stopImmediatePropagation(); + //return false; + } else if (alt) { + //console.log("double clicked"); + event.preventDefault(); + event.stopPropagation(); + event.stopImmediatePropagation(); + //return false; + } + else { + return; } - var panel = jQuery('#panel').show('slide') + + var panel = jQuery('#panel').show('slide'); panel.html(''); jQuery(".annotationsvg").css("opacity", 0.5); - jQuery("#"+event.target.id).css("opacity", 1); - var id = event.target.id - var url = "api/Data/getProperties.php?id="+id; + jQuery("#" + event.target.id).css("opacity", 1); + var id = event.target.id; + var url = "api/Data/getProperties.php?id=" + id; var content = "

Annotation Details

" - + "
"; - - jQuery.get(url, function(d){ - var data = {} - - try{ - data = JSON.parse(d)[0]; - } catch(e){ - console.log(e); - } - //console.log(data); - var features = []; - var properties = {}; - try { - if(data.properties.scalar_features) - features= data.properties.scalar_features[0].nv; - properties = data.properties.annotations; - } catch(e){ - console.log(e); - } - for(var i in properties){ - - if(i == "secret"){ - - } else { - var line = "
"+i+": " + properties[i]+"
"; - content+=line; + + "
"; + + jQuery.get(url, function (d) { + var data = {}; + + try { + data = JSON.parse(d)[0]; + } catch (e) { + console.log(e); + } + //console.log(data); + var features = []; + var properties = {}; + try { + if (data.properties.scalar_features) + features = data.properties.scalar_features[0].nv; + properties = data.properties.annotations; + console.log(properties); + } catch (e) { + console.log(e); } - - } - - for(var i =0; i< features.length; i++){ - var feature = features[i]; - var line = "
"+feature.name +"
"+feature.value+"
"; - content+=line; - } - - content += ""; - content += ""; - content +="
"; - var cancel = function () { - - jQuery('#panel').hide('slide') - - } - - panel.html(content); - - - jQuery("#cancelPanel").click(function(){cancel();}); - - jQuery("#deleteAnnot").click(function(e) { - - //$("#confirmDelete").css( - //console.log(data.provenance.analysis.source); - if(data.provenance.analysis.source == "human"){ - jQuery("#confirmDeleteButton").click(function(){ - var secret = jQuery("#deleteSecret").val(); - var payload = { - "id": id, - "secret": secret + for (var i in properties) { + + if (i == "secret") { + + } else { + var line = "
" + i + ": " + properties[i] + "
"; + content += line; } - - jQuery.ajax({ - url: 'api/Data/getProperties.php?id='+id, - type: 'DELETE', - data:(payload), - success: function(data){ - console.log(data); - jQuery("#panel").hide("slide"); - self.getMultiAnnot(); - } - }); - }); - } else { - alert("Can't delete computer generated segments"); + } - }); + + for (var i = 0; i < features.length; i++) { + var feature = features[i]; + var line = "
" + feature.name + "
" + feature.value + "
"; + content += line; + } + + // Section commented to disable Annotation deletion as per +// bug SBU-BMI/quip_distro#268 by Joe Balsamo +// if (ctrl) +// content += ""; +// else **When working join next line to this one again. + if (alt) + content += ""; + + + // Section commented to disable Annotation deletion as per +// bug SBU-BMI/quip_distro#268 by Joe Balsamo +// content += ""; + content += ""; + content += "
"; + var cancel = function () { + + jQuery('#panel').hide('slide') + + }; + + panel.html(content); + + + jQuery("#cancelPanel").click(function () { + cancel(); + }); +// Section commented to disable Annotation deletion as per +// bug SBU-BMI/quip_distro#268 by Joe Balsamo +// if (ctrl) { // Ctrl key for deletion of human generated annotation +// +// jQuery("#deleteAnnot").click(function (e) { +// +// //$("#confirmDelete").css( +// //console.log(data.provenance.analysis.source); +// if (data.provenance.analysis.source == "human") { +// jQuery("#confirmDeleteButton").click(function () { +// var secret = jQuery("#deleteSecret").val(); +// var payload = { +// "id": id, +// "secret": secret +// }; +// +// jQuery.ajax({ +// //url: 'api/Data/getProperties.php?id=' + id, +// url: 'api/Data/getPropertiesClone.php?id=' + id, +// type: 'DELETE', +// data: (payload), +// success: function (data) { +// console.log(data); +// jQuery("#panel").hide("slide"); +// self.getMultiAnnot(); +// } +// }); +// }); +// } else { +// alert("Can't delete computer generated segments"); +// } +// }); +// } }); - - }) + }); + + if (alt) { //new code go here to handle Alt key for featureScape view + } - /* - jQuery('.annotationsvg').mousedown(function (event) { - - switch (event.which) { - case 3: + /* + jQuery('.annotationsvg').mousedown(function (event) { + switch (event.which) { + case 3: - var panel = jQuery('#panel').show('slide') - panel.html(''); - var id = event.target.id - var url = "api/Data/getProperties.php?id="+id; - var content = "

Annotation Details

" - + "
"; - - jQuery.get(url, function(data){ - - var data = JSON.parse(data)[0]; - var properties = data.properties.annotations; - for(var i in properties){ - - if(i == "secret"){ - - } else { - var line = "
"+i+": " + properties[i]+"
"; - content+=line; + var panel = jQuery('#panel').show('slide') + panel.html(''); + + var id = event.target.id + var url = "api/Data/getProperties.php?id="+id; + var content = "

Annotation Details

" + + "
"; + + jQuery.get(url, function(data){ + + var data = JSON.parse(data)[0]; + var properties = data.properties.annotations; + for(var i in properties){ + + if(i == "secret"){ + + } else { + var line = "
"+i+": " + properties[i]+"
"; + content+=line; + } + } - - } - content += ""; - content +="
"; - var cancel = function () { - - jQuery('#panel').hide('slide') + content += ""; + content +="
"; + var cancel = function () { - } + jQuery('#panel').hide('slide') - panel.html(content); + } + panel.html(content); - jQuery("#cancelPanel").click(function(){cancel();}); + jQuery("#cancelPanel").click(function(){cancel();}); - }); - // jQuery("#panel").hide("slide") - break - } - }) - */ -} + + }); + // jQuery("#panel").hide("slide") + break + } + }) + */ +}; annotools.prototype.displayGeoAnnots = function () { - var geoJSONs = this.annotations - if (this.annotVisible) { - // var renderStartTime = performance.now() - this.generateSVG(geoJSONs) - // var renderEndTime = performance.now() - var renderStartTime = 9 - var renderEndTime = 23 - } -} + var geoJSONs = this.annotations; + if (this.annotVisible) { + // var renderStartTime = performance.now() + this.generateSVG(geoJSONs); + // var renderEndTime = performance.now() + var renderStartTime = 9; + var renderEndTime = 23 + } +}; diff --git a/js/annotationtoolslymph/osdAnnotationTools_Lymph.js b/js/annotationtoolslymph/osdAnnotationTools_Lymph.js index ad45fb996..5d0b52133 100644 --- a/js/annotationtoolslymph/osdAnnotationTools_Lymph.js +++ b/js/annotationtoolslymph/osdAnnotationTools_Lymph.js @@ -1,13 +1,16 @@ /* Copyright (C) 2012 Shaohuan Li , Ashish Sharma This file is part of Biomedical Image Viewer developed under the Google of Summer of Code 2012 program. - + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 - + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ +console.log("in osdAnnoTools.js"); + +console.log("osdAnnotationTools_Lymph.js"); var annotools = function (options) { this.AnnotationStore = new AnnotationStore(options.iid) @@ -22,7 +25,8 @@ var annotools = function (options) { this.iidDecoded = decodeURI(options.iid) this.canvas = options.canvas; // The canvas Element that The Use will be drawing annotatoins on. - this.iid = options.iid || null // The Image ID + this.iid = window.tissueId || null // The Image ID +// this.iid = options.iid || null // The Image ID this.annotVisible = true // The Annotations are Set to be visible at the First Loading this.mode = 'default' // The Mode is Set to Default @@ -51,7 +55,10 @@ var annotools = function (options) { this.lymphSuperuser = false; this.btn_revertWeight = document.getElementById('btn_revertWeight'); this.btn_saveWeight = document.getElementById('btn_saveHeatmapWeight'); + this.btn_saveQuality = document.getElementById('btn_saveHeatmapQuality'); this.btn_saveweight_help = document.getElementById('btn_heatmapweight_help'); + + /* this.rb_lymposbig = document.getElementById('LymPosBig'); this.rb_lymnegbig = document.getElementById('LymNegBig'); this.rb_lympos = document.getElementById('LymPos'); @@ -59,16 +66,37 @@ var annotools = function (options) { this.rb_tumpos = document.getElementById('TumorPos'); this.rb_tumneg = document.getElementById('TumorNeg'); this.rb_move = document.getElementById('rb_Moving'); + */ + this.rb_algoabig = document.getElementById('AlgoABig'); + this.rb_algobbig = document.getElementById('AlgoBBig'); + this.rb_algoa = document.getElementById('AlgoA'); + this.rb_algob = document.getElementById('AlgoB'); + this.rb_algoapoly = document.getElementById('AlgoAPoly'); + this.rb_algobpoly = document.getElementById('AlgoBPoly'); + this.rb_algoabig.addEventListener('click', this.radiobuttonChange.bind(this), false); + this.rb_algobbig.addEventListener('click', this.radiobuttonChange.bind(this), false); + this.rb_algoa.addEventListener('click', this.radiobuttonChange.bind(this), false); + this.rb_algob.addEventListener('click', this.radiobuttonChange.bind(this), false); + this.rb_algoapoly.addEventListener('click', this.radiobuttonChange.bind(this), false); + this.rb_algobpoly.addEventListener('click', this.radiobuttonChange.bind(this), false); + /* this.rb_lymposbig.addEventListener('click', this.radiobuttonChange.bind(this), false); this.rb_lymnegbig.addEventListener('click', this.radiobuttonChange.bind(this), false); this.rb_lympos.addEventListener('click', this.radiobuttonChange.bind(this), false); this.rb_lymneg.addEventListener('click', this.radiobuttonChange.bind(this), false); this.rb_tumpos.addEventListener('click', this.radiobuttonChange.bind(this), false); this.rb_tumneg.addEventListener('click', this.radiobuttonChange.bind(this), false); + */ + var radios = document.getElementsByName("marktype"); + for( i = 0; i < radios.length; i++ ) { + radios[i].addEventListener('click', this.radiobuttonChange.bind(this), false); + } + this.rb_move = document.getElementById('rb_Moving'); this.rb_move.addEventListener('click', this.radiobuttonChange.bind(this), false); this.btn_revertWeight.addEventListener('click', this.revertWeight.bind(this), false); this.btn_saveWeight.addEventListener('click', this.saveHeatmapWeight.bind(this), false); + this.btn_saveQuality.addEventListener('click', this.saveHeatmapQuality.bind(this), false); this.btn_saveweight_help.addEventListener('click', function(){alert('\ This panel allows you to adjust the automatic lymphocyte prediction results for this slide, with the options described below.\n\n\ Lymphocyte Sensitivity bar:\n Ddjust the sensitivity of lymphocyte prediction.\n\ @@ -141,8 +169,49 @@ To save/cancel your work, use the buttons described below:\n\ overwrite them by drawing new markings.\ ');}, false); + this.btn_savequalmark_var = document.getElementById('btn_savequalmark'); + this.btn_savequalmark_var.addEventListener('click', this.markSaveClick.bind(this), false); + this.btn_undoqualmark_var = document.getElementById('btn_undoqualmark'); + this.btn_qualmark_help_var = document.getElementById('btn_qualmark_help'); + this.btn_undoqualmark_var.addEventListener('click', this.undoStroke.bind(this), false); + this.btn_qualmark_help_var.addEventListener('click', function(){alert('\ +This panel provides tools to manually mark segmentation quality heatmaps as Algorithm A or B.\n\n\ +If you are unsatisfied with the segmentation quality prediction result, please polish it using options described below:\n\ + AlgoA (draw thin line):\n\ + Draw lines across quality squares.\n\ + After saved, squares crossed by the line\n\ + will be marked as Algorithm A squares.\n\ + AlgoB (draw thin line):\n\ + Draw lines across quality squares.\n\ + After saved, squares crossed by the line\n\ + will be marked as Algorithm B squares.\n\ + AlgoA (draw thick line):\n\ + Draw lines across quality squares.\n\ + After saved, squares close to the line\n\ + will be marked as Algorithm A squares.\n\ + AlgoB (draw thick line):\n\ + Draw lines across quality squares.\n\ + After saved, squares close to the line\n\ + will be marked as Algorithm B squares.\n\ +Please indicate quality regions using options described below:\n\ + AlgoA (draw polygon):\n\ + Draw curves around Algorithm A regions of this slide.\n\ + Regions not included will not be changed\n\ + AlgoB (draw polygon):\n\ + Draw curves around Algorithm B regions of this slide.\n\ + Regions not included will not be changed\n\n\ +To save/cancel your work, use the buttons described below:\n\ + Save:\n\ + Save all markings, and continue to mark.\n\ + Cancel:\n\ + Cancel the most recent, unsaved marking.\n\ + To change saved markings, you can simply\n\ + overwrite them by drawing new markings.\ +');}, false); + this.heatmap_opacity = 0.4; this.heatmapColor = ['#feedde','#fecc5c','#fd8d3c','#bd0026', '#33b5ff']; + this.heatmapColorQuality = ['#d7191c','#fdae61','#ffffbf','#abd9e9','#2c7bb6']; this.multipleHeatmapColor = []; this.cb_checked = [false, false, false]; this.heat_weight = [0.77, 1.00, 0.15]; @@ -192,7 +261,7 @@ To save/cancel your work, use the buttons described below:\n\ cb1.style.visibility = "hidden"; cb2.style.visibility = "hidden"; cb3.style.visibility = "hidden"; - + // Turn on-off lymphocyte heat this.lymheat = true; @@ -237,7 +306,7 @@ To save/cancel your work, use the buttons described below:\n\ this.drawLayer = jQuery('
', { html: "", styles: { - position: 'absolute', + position: 'absolute', 'z-index': 1 } }) @@ -281,36 +350,43 @@ annotools.prototype.destroyMarkups = function (viewer) { } } -annotools.prototype.getMultiAnnot = function (viewer) { - var opa = [] - - var val1 = '' - var val2 = '' - var val3 = '' +annotools.prototype.oneExecIDChosenFiltered = function (algorithms,prefix,message,callback) { + if (algorithms) + { + filtered = algorithms.filter(function (alg) { + return alg.startsWith(prefix); + }); + qcount = filtered.length; + //console.log(filtered); - + if (qcount == 1) { + callback(filtered[0]); + } else if (qcount != 0) { + alert(message); + } - var algorithms = [] + } +} - /* - if (jQuery('#tree').attr('algotree')) { - var selalgos = jQuery('#tree').fancytree('getTree').getSelectedNodes() - console.log("selalgos is: "+selalgos); - for (i = 0; i < selalgos.length; i++) { - //console.log(selalgos[i]) - algorithms.push(selalgos[i].refKey) - console.log("selalgos refKey is: "+selalgos[i].refKey); - // opa["Val" + (i + 1).toString()] = selalgos[i].refKey - } - }*/ - - console.log(ALGORITHM_LIST); - console.log(SELECTED_ALGORITHM_LIST); - SELECTED_ALGORITHM_LIST = SELECTED_ALGORITHM_LIST.sort(); - console.log("...."); - algorithms = SELECTED_ALGORITHM_LIST; - - +annotools.prototype.getMultiAnnot = function (viewer) { + + if(appid == "qualheat") { + this.oneExecIDChosenFiltered(algorithms,"quality_","Select only one 'quality' algorithm.",this.loadHeatmapQuality); + } +// +// //console.log(algorithms); +// +// filtered = algorithms.filter(function (alg) { +// return alg.startsWith("quality_"); +// }); +// qcount = filtered.length; +// //console.log(filtered); +// +// if (qcount == 1) { +// this.loadHeatmapQuality(filtered[0]); +// } else if (qcount != 0) { +// alert("Select only one 'quality' algorithm."); +// } //console.log(algorithms); //console.log(this.imagingHelper._viewportWidth); //console.log(this.imagingHelper._viewportHeight); @@ -332,30 +408,70 @@ annotools.prototype.getMultiAnnot = function (viewer) { var area = (max.x - origin.x) * (max.y - origin.y) //algorithms.push('test') - var t1 = 0 - if (algorithms.length) { + var t1 = 0; + if (SELECTED_ALGORITHM_LIST.length) { + SELECTED_ALGORITHM_LIST = SELECTED_ALGORITHM_LIST.sort(); + var algorithms = SELECTED_ALGORITHM_LIST; + var myList = OVERLAY_LIST; + + self.fetchAnnots(area, algorithms, myList); + } else { + self.setupHandlers(); + self.destroyMarkups(); + // destroy canvas + } + +}; + +annotools.prototype.filterit = function (a, b) { + + var aa = []; + var bb = []; + for (var i = 0; i < b.length; i++) { + bb.push(b[i].execid); + + } + + // If we've already displayed the tiles + // remove it from the "todo" list. + for (var i = 0; i < a.length; i++) { + var idx = bb.indexOf(a[i]); + if (idx < 0) { + aa.push(a[i]); + + } + } + + return aa; +}; + +annotools.prototype.fetchAnnots = function (area, SELECTED_ALGORITHM_LIST, OVERLAY_LIST) { + var self = this; + var algorithms = self.filterit(SELECTED_ALGORITHM_LIST, OVERLAY_LIST); + //console.log("**** algorithms ****", algorithms); + + if (algorithms.length) { + if (this.toolBar !== undefined && this.toolBar !== null) { this.toolBar.titleButton.hide(); this.toolBar.ajaxBusy.show(); } - //this.toolBar.titleButton.hide() - //this.toolBar.ajaxBusy.show() - this.annotations = this.AnnotationStore.fetchAnnotations(this.x1, this.y1, this.x2, this.y2, area, algorithms, function (data) { - // console.log(data) - self.annotations = data - self.displayGeoAnnots() - self.setupHandlers() - var t2 = 10 - - self.toolBar.titleButton.show() - self.toolBar.ajaxBusy.hide() - }) - } else { - self.setupHandlers() - self.destroyMarkups() - // destroy canvas - } -} + + this.annotations = this.AnnotationStore.fetchAnnotations(self.x1, self.y1, self.x2, self.y2, area, algorithms, function (data) { + self.annotations = data; + self.displayGeoAnnots(); + self.setupHandlers(); + + self.toolBar.titleButton.show(); + self.toolBar.ajaxBusy.hide(); + }); + + } else { + self.setupHandlers(); + self.destroyMarkups(); + // destroy canvas + } +}; annotools.prototype.getAnnot = function (viewer) // Get Annotation from the API { @@ -602,7 +718,7 @@ annotools.prototype.createWorkOrder = function () { // The canvas context var ctx = this.drawCanvas.getContext('2d') - + this.removeMouseEvents() var started = false var min_x,min_y,max_x,max_y,w,h @@ -664,7 +780,7 @@ annotools.prototype.createWorkOrder = function () { loc[1] = parseFloat(newAnnot.y) newAnnot.loc = loc - // convert to geojson + // convert to geojson // var geoNewAnnot = this.convertRectToGeo(newAnnot) geoNewAnnot = newAnnot this.promptForWorkOrder(geoNewAnnot, 'new', this, ctx) @@ -970,8 +1086,8 @@ annotools.prototype.relativeToGlobal = function () { originalCoord.y = object.getAttribute('y') originalCoord.width = object.getAttribute('width') originalCoord.height = object.getAttribute('height') - originalCoord.zoom = viewer.viewport.getZoom() - this.annotationHandler.originalCoords[object.id] = originalCoord + originalCoord.zoom = viewer.viewport.getZoom() + this.annotationHandler.originalCoords[object.id] = originalCoord var bbox = object.getBBox() var objectCenterPt = new OpenSeadragon.Point(bbox.x + bbox.width / 2, bbox.y + bbox.height / 2) var objectCenterRelPt = this.viewer.viewport.pointFromPixel(objectCenterPt) @@ -1017,7 +1133,7 @@ annotools.prototype.setupHandlers = function () { //console.log('setting up handlers') var root = document.getElementsByTagName('svg')[0] - // console.log(root); + // console.log(root); if (root != undefined) { if (navigator.userAgent.toLowerCase().indexOf('webkit') >= 0) { window.addEventListener('mousewheel', this.annotationHandler.handleMouseWheel, false) // Chrome/Safari @@ -1169,7 +1285,7 @@ annotools.prototype.saveAnnot = function (annotation) // Save Annotations //console.log(res) if(res == "unauthorized"){ alert("Error saving markup! Wrong secret"); - } else { + } else { //alert("Successfully saved markup!"); } //console.log(err) @@ -1355,12 +1471,12 @@ annotools.prototype.convertFromNative = function (annot, end) { var lastPolyPoint = new OpenSeadragon.Point(parseFloat(last_poly_split[0]), parseFloat(last_poly_split[1])) points += this.imagingHelper.physicalToLogicalX(lastPolyPoint.x) + ',' + this.imagingHelper.physicalToLogicalY(lastPolyPoint.y) - + if ( typeof(end) !== 'undefined') { var x_end = end.x; var y_end = end.y; } - + var nativeX_end = this.imagingHelper.physicalToLogicalX(x_end) var nativeY_end = this.imagingHelper.physicalToLogicalY(y_end) var nativeX = this.imagingHelper.physicalToLogicalX(x) @@ -1543,7 +1659,7 @@ annotools.prototype.drawRectangle = function (ctx) { console.log(newAnnot); - // convert to geojson + // convert to geojson var geoNewAnnot = this.convertRectToGeo(newAnnot) // geoNewAnnot = newAnnot this.promptForAnnotation(geoNewAnnot, 'new', this, ctx); @@ -1922,6 +2038,7 @@ annotools.prototype.populateForm = function (annotationTemplateJson, annotationT } else { var options = val['enumerable'].replace(/ /g, '').split(',') if (val['multi'] == 'true' && mode != 'filter') { + console.log("adding Checkbox"); for (var i = 0; i < options.length; i++) { form += "
" + " " + "
") - - + + jQuery("#controlInvert").on("click", function(){ viewer.setFilterOptions({ filters: { processors: OpenSeadragon.Filters.INVERT() } }) - }); - + }); + jQuery("#controlSobel").on("click", function(){ viewer.setFilterOptions({ filters: { @@ -1985,7 +2102,7 @@ annotools.prototype.showFilterControls = function(newAnnot, mode, annotools, ctx ] } }) - }); + }); jQuery("#controlThreshhold").on("change", function(){ var threshhold = 1*jQuery(this).val() console.log(threshhold) @@ -1994,7 +2111,7 @@ annotools.prototype.showFilterControls = function(newAnnot, mode, annotools, ctx processors: OpenSeadragon.Filters.THRESHOLDING(threshhold) } }) - console.log(viewer); + console.log(viewer); }) jQuery("#controlContrast").on("change", function(){ @@ -2005,7 +2122,7 @@ annotools.prototype.showFilterControls = function(newAnnot, mode, annotools, ctx processors: OpenSeadragon.Filters.CONTRAST(contrast) } }) - console.log(viewer); + console.log(viewer); }) jQuery("#controlBright").on("change", function(){ //console.log(viewer) @@ -2082,7 +2199,7 @@ annotools.prototype.promptForWorkOrder = function (newAnnot, mode, annotools, ct annotools.drawLayer.hide() annotools.addMouseEvents() // annotools.removeMouseEvents() - // annotools.getMultiAnnot(); + // annotools.getMultiAnnot(); var username = 'lastlegion' var execution_id = jQuery('#order-execution_id').val() @@ -2138,7 +2255,7 @@ annotools.prototype.promptForWorkOrder = function (newAnnot, mode, annotools, ct var order = { "type": "order", - "data":{ + "data":{ "created_on": Date.now(), "created_by": "lastlegion" } @@ -2219,7 +2336,7 @@ annotools.prototype.promptForWorkOrder = function (newAnnot, mode, annotools, ct annotools.drawLayer.hide() annotools.addMouseEvents() // annotools.removeMouseEvents() - // annotools.getMultiAnnot(); + // annotools.getMultiAnnot(); var username = 'lastlegion' var execution_id = jQuery('#order-execution_id').val() @@ -2275,7 +2392,7 @@ annotools.prototype.promptForWorkOrder = function (newAnnot, mode, annotools, ct var order = { "type": "order", - "data":{ + "data":{ "created_on": Date.now(), "created_by": "lastlegion" } @@ -2505,7 +2622,7 @@ annotools.prototype.downloadROI = function(){ // The canvas context var ctx = this.drawCanvas.getContext('2d') - + this.removeMouseEvents() var started = false var min_x,min_y,max_x,max_y,w,h @@ -2567,7 +2684,7 @@ annotools.prototype.downloadROI = function(){ loc[1] = parseFloat(newAnnot.y) newAnnot.loc = loc - // convert to geojson + // convert to geojson // var geoNewAnnot = this.convertRectToGeo(newAnnot) geoNewAnnot = newAnnot this.promptForDownload(geoNewAnnot, 'new', this, ctx) @@ -2599,7 +2716,7 @@ annotools.prototype.promptForDownload = function(newAnnot, mode, annotools, ctx) url = iipSrv + fileLocationReal + "/"+x+ ","+y+","+w+","+h +"/full/0/default.jpg"; panel.html(function () { - return "

Download ROI

  • x: " + return "

    Download ROI

    • x: " + x + "
    • y: " + y + "
    • w: " + w + "
    • h: " + h + "

    Error! The ROI was too large. We've resized it to 2000 x 2000 tile
    "; }); @@ -2609,13 +2726,13 @@ annotools.prototype.promptForDownload = function(newAnnot, mode, annotools, ctx) panel.html(function () { - return "

    Download ROI

    • x: " + return "

      Download ROI

      • x: " + x + "
      • y: " + y + "
      • w: " + w + "
      • h: " + h + "

      "; }); } jQuery('#cancelWorkOrder').click(function () { - + jQuery('#panel').hide() annotools.drawLayer.hide() annotools.addMouseEvents() @@ -2624,14 +2741,14 @@ annotools.prototype.promptForDownload = function(newAnnot, mode, annotools, ctx) console.log(fileLocation); console.log(url); jQuery('#submitWorkOrder').click(function () { - + // annotools.drawCanvas.removeEvents('mouseup') // annotools.drawCanvas.removeEvents('mousedown') // annotools.drawCanvas.removeEvents('mousemove') annotools.drawLayer.hide() annotools.addMouseEvents() // annotools.removeMouseEvents() - // annotools.getMultiAnnot(); + // annotools.getMultiAnnot(); var username = 'lastlegion' var execution_id = jQuery('#order-execution_id').val() @@ -2771,19 +2888,19 @@ annotools.prototype.saveHeatmapWeight = function(event) annotools.prototype.saveHeatmapWeight = function(event) { console.log('Start saveHeatmapWeight'); - + var self = this; var weightData = { 'case_id': self.iid, 'lymweight': this.heat_weight[0], 'necweight': this.heat_weight[1], 'smoothness': this.heat_weight[2], - 'username': this.username + 'username': this.username }; - + //Check if record for this case_id and this username already exists in mongodb var url1 = "api/Data/lymphocyteData.php?case_id="+ self.iid + "&username=" + this.username; - + // Debug console.log(url1); @@ -2792,7 +2909,7 @@ annotools.prototype.saveHeatmapWeight = function(event) var data = JSON.parse(d); console.log('Retrived heat weights: ' + JSON.stringify(data[0])); console.log("Fetched data length: " + data.length); - + if (data.length > 0){ console.log('Record exists'); alert ('This heatmap has been locked'); @@ -2811,13 +2928,13 @@ annotools.prototype.saveHeatmapWeight = function(event) document.getElementById('div_weight_locked').innerHTML = 'Locked'; alert('Saved heatmap weights'); } - }) + }) } } catch (e){ console.log('ERROR'); console.log(e); } - + }); } @@ -2827,10 +2944,10 @@ annotools.prototype.loadHeatmapWeight = function() //console.log('Load heatmap weights'); //console.log(self.iid); //console.log(this.username); - + // Start API var url1 = "api/Data/lymphocyteData.php?case_id="+ self.iid +"&username=" + this.username; - + // Debug console.log(url1); @@ -2840,22 +2957,22 @@ annotools.prototype.loadHeatmapWeight = function() var data = JSON.parse(d); //console.log('Retrived heat weights: ' + JSON.stringify(data[0])); //console.log("Fetched data length: " + data.length); - + // Start weights var sl1 = document.getElementById('slide1'); var sl2 = document.getElementById('slide2'); var sl3 = document.getElementById('slide3'); var div_lock = document.getElementById('div_weight_locked'); console.log(data); - + if ( data.length > 0) { - + //console.log("case_id" + data[0].case_id); //console.log("lymweight" + data[0].lymweight); //console.log("necweight" + data[0].necweight); //console.log("smoothness" + data[0].smoothness); //console.log("username" + data[0].username); - + var lym = data[0].lymweight; var nec = data[0].necweight; var smh = data[0].smoothness; @@ -2873,7 +2990,7 @@ annotools.prototype.loadHeatmapWeight = function() } if (smh){ - smh = (parseFloat(smh) * 100).toString() + '%'; + smh = (parseFloat(smh) * 100).toString() + '%'; }else { smh = '0%'; } @@ -2897,7 +3014,7 @@ annotools.prototype.loadHeatmapWeight = function() console.log(e); } }); - + // Wait for the load weight transfering data var start = new Date().getTime(); var delay = 200; @@ -2907,6 +3024,139 @@ annotools.prototype.loadHeatmapWeight = function() self.getMultiAnnot(); } +annotools.prototype.saveHeatmapQuality = function(event) +{ + var eid = ""; + console.log('Start saveHeatmapQuality'); + + algorithms = SELECTED_ALGORITHM_LIST; + + //console.log(algorithms); + + filtered = algorithms.filter(function (alg) { + return alg.startsWith("quality_"); + }); + qcount = filtered.length; + //console.log(filtered); + + if (qcount == 1) { + eid = filtered[0]; + } else if (qcount != 0) { + alert("Select only one 'quality' algorithm."); + return 0; + } + var self = this; + var qualityData = { + 'case_id': self.iid, + 'exec_id': eid, + 'low': qualthresholds.low, + 'high': qualthresholds.high, + 'username': this.username + }; + + console.log(qualityData); + + //Check if record for this case_id and this username already exists in mongodb + var url1 = "api/Data/heatmapData.php?case_id="+ self.iid + "&exec_id=" + eid; + + // Debug + console.log(url1); + + jQuery.get(url1, function(d){ + try{ + var data = JSON.parse(d); + console.log('Retrived qual weights: ' + JSON.stringify(data[0])); + console.log("Fetched data length: " + data.length); + + if (data.length > 0){ + console.log('Record exists'); + alert ('This heatmap has been locked'); + } + else { + jQuery.ajax({ + 'type': 'POST', + url: 'api/Data/heatmapData.php', + data: qualityData, + success: function (res, err) { + //console.log("response: ") + console.log(res) + console.log(err) + + console.log('successfully posted') + document.getElementById('div_quality_locked').innerHTML = 'Locked'; + alert('Saved heatmap quality thresholds'); + } + }) + } + } catch (e){ + console.log('ERROR'); + console.log(e); + } + + }); +} + +annotools.prototype.loadHeatmapQuality = function(eid) +{ + var self = this; + console.log('Load heatmap quality'); + console.log(self.iid); + + // Start API + var url1 = "api/Data/heatmapData.php?case_id="+ self.iid +"&exec_id=" + eid; + + // Debug + console.log(url1); + + jQuery.get(url1, function(d){ + + try{ + var data = JSON.parse(d); + var mySlider = jQuery("#qslider")[0]; + //console.log('Retrived heat weights: ' + JSON.stringify(data[0])); + //console.log("Fetched data length: " + data.length); + + var div_qlock = document.getElementById('div_quality_locked'); + // Start weights + console.log(data); + + if ( data.length > 0) { + var low = data[0].low; + var high = data[0].high; + + if (low){ + mySlider.noUiSlider.set([parseInt(low)]); + }else { + mySlider.noUiSlider.set([parseInt(30)]); + } + + if (high){ + mySlider.noUiSlider.set([null,parseInt(high)]); + }else { + mySlider.noUiSlider.set([null,parseInt(70)]); + } + + div_qlock.innerHTML = "Locked"; + }else { + console.log('go else'); + mySlider.noUiSlider.set([30,70]); + div_qlock.innerHTML = "Free"; + } + } catch (e){ + console.log('ERROR'); + console.log(e); + } + }); + + // Wait for the load weight transfering data + var start = new Date().getTime(); + var delay = 200; + while (new Date().getTime() < start + delay); + //console.log(document.getElementById('slide1').style.width); + //console.log(document.getElementById('div_weight_locked').innerHTML); + //self.getMultiAnnot(); +} + /* annotools.prototype.loadHeatmapWeight = function() { @@ -2924,7 +3174,7 @@ annotools.prototype.loadHeatmapWeight = function() var sl3 = document.getElementById('slide3'); var div_lock = document.getElementById('div_weight_locked'); console.log(data); - if (!data.startsWith('NaN')) { + if (!data.startsWith('NaN')) { parts = data.split('\n'); //arr = [parseFloat(parts[0]), parseFloat(parts[1])]; //var sl1 = document.getElementById('slide1'); @@ -3013,11 +3263,11 @@ annotools.prototype.isLymphSuperuser = function() { var self = this; //console.log("lymphUser.superuserRole: " + lymphUser.superuserRole); - + self.username = self.username.toLowerCase(); var role = lymphUser.superuserRole; var url = "api/Data/lymphocyteSuperusers.php?email=" + self.username + "&role=" + role; - + // Debug console.log(url); @@ -3025,39 +3275,39 @@ annotools.prototype.isLymphSuperuser = function() try { var data = JSON.parse(d); console.log("Fetched data users length: " + data.length); - + // Start users console.log(data); //console.log("email: " + data[0].email); //console.log("role: " + data[0].role); - + if ( data.length > 0) { - self.lymphSuperuser = true; + self.lymphSuperuser = true; } console.log('self.lymphSuperuser: ' + self.lymphSuperuser); - + } catch (e){ console.log('ERROR'); console.log(e); } - }); + }); } annotools.prototype.loadChangeUsername = function() { var self = this; - + console.log('loadChangeUsername ' + self.username); - + var url1 = "api/Data/getLymphocyteDataByCaseId.php?case_id=" + self.iid; - + // Debug console.log(url1); jQuery.get(url1, function(d) { - + var container = jQuery('#switchuserpanel'); - + jQuery('#closeSwitchUser').click(function (e) { e.preventDefault(); jQuery('#switchuserpanel').hide('slide'); @@ -3066,10 +3316,10 @@ annotools.prototype.loadChangeUsername = function() try { var data = JSON.parse(d); //console.log("Fetched data users length: " + data.length); - + // Start users console.log(data); - + if ( data.length > 0) { for ( var j = 0; j < data.length; j++ ) { //console.log("username: " + data[j].username); @@ -3077,9 +3327,9 @@ annotools.prototype.loadChangeUsername = function() if (data[j].username.trim() === self.username) { container.append('
      '); }else { - container.append('
      '); + container.append('
      '); } - + //switch var switch_user_eles = document.getElementById('switch_user_' + j.toString()); if (switch_user_eles != null) { @@ -3088,12 +3338,13 @@ annotools.prototype.loadChangeUsername = function() break; } } - } - } + } + } else { + container.append('
      There are no users with finalized data to view! Instruct the users to set weight thresholds and click finalize to make them available.
      '); + } } catch (e){ console.log('ERROR'); console.log(e); } }); } - diff --git a/js/annotationtoolslymph/osdAnnotationTools_Marking.js b/js/annotationtoolslymph/osdAnnotationTools_Marking.js index 58ec269bb..904ba15bd 100644 --- a/js/annotationtoolslymph/osdAnnotationTools_Marking.js +++ b/js/annotationtoolslymph/osdAnnotationTools_Marking.js @@ -7,9 +7,12 @@ annotools.prototype.drawMarking = function (ctx) { this.color_arr = []; this.anno_arr = []; this.marktype_arr = []; + this.markeid_arr = []; this.markwidth_arr = []; this.current_canvasContext = ctx; this.mark_type = 'LymPos'; + this.mark_eid = ''; + this.algorithm = []; // Variables for broken markups this.rawAnnotArray = []; @@ -33,8 +36,22 @@ annotools.prototype.drawMarking = function (ctx) { ctx.beginPath(); ctx.moveTo(relativeStartPoint.x, relativeStartPoint.y); + // Added for debug + //console.log($('input[name="marktype"]:checked').val()); + console.log(jQuery('input[name="marktype"]:checked').val()); + console.log(jQuery("#LymPos").attr("wed")); + var drawn_linewidth = 3; + // Replacement code for below if statements + selectedRadio = "#" + jQuery('input[name="marktype"]:checked').val(); + console.log(selectedRadio); + ctx.strokeStyle = jQuery(selectedRadio).attr("color"); + this.mark_type = jQuery(selectedRadio).attr("value"); + this.markupline_width = jQuery(selectedRadio).attr("lineaffect"); + drawn_linewidth = jQuery(selectedRadio).attr("linewidth"); + // Check what radio box is checked + if (jQuery("#LymPosBig").is(':checked')) { ctx.strokeStyle = 'red'; @@ -76,7 +93,63 @@ annotools.prototype.drawMarking = function (ctx) { ctx.strokeStyle = 'lime'; this.mark_type = 'TumorNeg'; } - console.log(this.mark_type); + +/* For Quality Heatmaps + + if (jQuery("#AlgoABig").is(':checked')) + { + ctx.strokeStyle = 'red'; + this.mark_type = 'AlgoA'; + this.markupline_width = 2; + drawn_linewidth = 6; + } + + if (jQuery("#AlgoBBig").is(':checked')) + { + ctx.strokeStyle = 'blue'; + this.mark_type = 'AlgoB'; + this.markupline_width = 2; + drawn_linewidth = 6; + } + + if (jQuery("#AlgoA").is(':checked')) + { + ctx.strokeStyle = 'red'; + this.mark_type = 'AlgoA'; + this.markupline_width = 1; + } + + if (jQuery("#AlgoB").is(':checked')) + { + ctx.strokeStyle = 'blue'; + this.mark_type = 'AlgoB'; + this.markupline_width = 1; + } + + if (jQuery("#AlgoAPoly").is(':checked')) + { + ctx.strokeStyle = 'orange'; + this.mark_type = 'AlgoAP'; + } + + if (jQuery("#AlgoBPoly").is(':checked')) + { + ctx.strokeStyle = 'lime'; + this.mark_type = 'AlgoBP'; + } +*/ console.log(this.mark_type); + + SELECTED_ALGORITHM_LIST = SELECTED_ALGORITHM_LIST.sort(); + + algorithms = SELECTED_ALGORITHM_LIST; + + if(appid == "qualheat") { + var that = this; + this.oneExecIDChosenFiltered(algorithms,"quality_","Select only one 'quality' algorithm.", function (qalgo) { + that.mark_eid = qalgo; + console.log("This works. "+qalgo); + }); + } this.color_arr.push(ctx.strokeStyle); console.log(this.color); @@ -142,7 +215,7 @@ annotools.prototype.drawMarking = function (ctx) { color: this.color, loc: [] } - + var globalNumbers = JSON.parse(this.convertFromNative(newAnnot, endRelativeMousePosition)) newAnnot.x = globalNumbers.nativeX newAnnot.y = globalNumbers.nativeY @@ -157,12 +230,15 @@ annotools.prototype.drawMarking = function (ctx) { this.rawAnnotArray.push(newAnnot); var geojsonAnnot = this.convertPencilToGeo(newAnnot) geojsonAnnot.object_type = 'marking'; + //console.log(geojsonAnnot); //this.promptForAnnotation(geojsonAnnot, 'new', this, ctx) this.anno_arr.push(geojsonAnnot); this.marktype_arr.push(this.mark_type); + this.markeid_arr.push(this.mark_eid); this.markwidth_arr.push(this.markupline_width); //this.saveMarking(geojsonAnnot, this.mark_type); + console.log("Algorithm: "+ this.mark_algo); /* Change button back to inactive*/ jQuery("canvas").css("cursor", "default"); @@ -177,6 +253,7 @@ annotools.prototype.breakAndConvertToGeo = function () // Refresh this.anno_arr this.anno_arr = []; this.marktype_broken_arr = []; + this.markeid_broken_arr = []; this.markwidth_broken_arr = []; for (i = 0; i< this.rawAnnotArray.length; i++) { @@ -210,6 +287,7 @@ annotools.prototype.breakAndConvertToGeo = function () this.anno_arr.push(geojsonAnnot); this.marktype_broken_arr.push(this.marktype_arr[i]); this.markwidth_broken_arr.push(this.markwidth_arr[i]); + this.markeid_broken_arr.push(this.markeid_arr[i]); } } } @@ -226,12 +304,13 @@ annotools.prototype.saveMarking = function (newAnnot, mark_type) { this.addnewAnnot(newAnnot); } -annotools.prototype.saveMarking_arr = function (newAnnot_arr, mark_type_arr, mark_width_arr) { +annotools.prototype.saveMarking_arr = function (newAnnot_arr, mark_type_arr, mark_width_arr, mark_eid_arr) { for (iAnn = 0; iAnn < newAnnot_arr.length; iAnn++) { var val = { 'secret': 'mark1', 'mark_type': mark_type_arr[iAnn], 'mark_width': mark_width_arr[iAnn], + 'mark_eid': mark_eid_arr[iAnn], 'username': this.username } newAnnot_arr[iAnn].properties.annotations = val; @@ -245,7 +324,7 @@ annotools.prototype.markSave = function (notification, isSetNormalMode) { return; this.breakAndConvertToGeo(); - this.saveMarking_arr(this.anno_arr, this.marktype_broken_arr, this.markwidth_broken_arr); + this.saveMarking_arr(this.anno_arr, this.marktype_broken_arr, this.markwidth_broken_arr, this.markeid_broken_arr); if (notification == true) { alert("Saved markup"); } @@ -278,6 +357,7 @@ annotools.prototype.undoStroke = function () { this.anno_arr.pop(); this.rawAnnotArray.pop(); this.marktype_arr.pop(); + this.markeid_arr.pop(); this.markwidth_arr.pop(); console.log(this.color_arr); this.reDrawCanvas(); @@ -311,7 +391,6 @@ annotools.prototype.switchUserRadiobuttonChange = function(event) { annotools.prototype.radiobuttonChange = function(event) { console.log('rb changed'); - console.log(this.marking_choice); var self = this; if (event.target.id == 'rb_Moving') { @@ -343,6 +422,7 @@ annotools.prototype.radiobuttonChange = function(event) { } } this.marking_choice = event.target.id; + console.log(this.marking_choice); } @@ -391,7 +471,7 @@ annotools.prototype.break_drawings = function(nativepoints) { coor_str += ' ' + added_X.toFixed(6) + ',' + added_Y.toFixed(6); n_point ++; } - + coor_str += ' ' + x.toFixed(6) + ',' + y.toFixed(6); n_point ++; @@ -503,6 +583,7 @@ annotools.prototype.calculateIntersect = function(high_res) { var annotations = this.annotations; var labels = []; + var label = 0; var label_dates = []; var id = []; var cx = []; @@ -521,7 +602,7 @@ annotools.prototype.calculateIntersect = function(high_res) { var annotation = annotations[i]; labels.push(0); label_dates.push(0); - if (annotation.object_type == 'heatmap_multiple') { + if ((annotation.object_type == 'heatmap_multiple')||(annotation.object_type == 'heatmap_quality')) { var nativepoints = annotation.geometry.coordinates[0]; id.push(i); cx.push((nativepoints[0][0] + nativepoints[2][0])/2.0); @@ -573,12 +654,17 @@ annotools.prototype.calculateIntersect = function(high_res) { label = 1; } else if (annotation.properties.annotations.mark_type == 'LymNeg') { label = -1; + } else if (annotation.properties.annotations.mark_type == 'AlgoA') { + label = -1; + } else if (annotation.properties.annotations.mark_type == 'AlgoB') { + label = 1; } else { continue; } + var date = this.getDate(annotation); - + if (high_res) { var mark_width = Math.pow(annotation.properties.annotations.mark_width, 2); } else { @@ -592,7 +678,7 @@ annotools.prototype.calculateIntersect = function(high_res) { if ((Math.abs(cx[xy_i] - x) <= disx*mark_width) && (Math.abs(cy[xy_i] - y) <= disy*mark_width)) { if (date > label_dates[id[xy_i]]) { label_dates[id[xy_i]] = date; - labels[id[xy_i]] = label; + labels[id[xy_i]] = { 'label': label, 'eid': annotation.properties.annotations.mark_eid }; } } } diff --git a/js/filteringtools/openseadragon-filtering.BAK.js b/js/filteringtools/openseadragon-filtering.BAK.js new file mode 100644 index 000000000..124067b1b --- /dev/null +++ b/js/filteringtools/openseadragon-filtering.BAK.js @@ -0,0 +1,447 @@ +/* + * This software was developed at the National Institute of Standards and + * Technology by employees of the Federal Government in the course of + * their official duties. Pursuant to title 17 Section 105 of the United + * States Code this software is not subject to copyright protection and is + * in the public domain. This software is an experimental system. NIST assumes + * no responsibility whatsoever for its use by other parties, and makes no + * guarantees, expressed or implied, about its quality, reliability, or + * any other characteristic. We would appreciate acknowledgement if the + * software is used. + */ + +/** + * + * @author Antoine Vandecreme + */ +;(function () { + 'use strict' + + var $ = window.OpenSeadragon + if (!$) { + $ = require('openseadragon') + if (!$) { + throw new Error('OpenSeadragon is missing.') + } + } + // Requires OpenSeadragon >=2.1 + if (!$.version || $.version.major < 2 || + $.version.major === 2 && $.version.minor < 1) { + throw new Error( + 'Filtering plugin requires OpenSeadragon version >= 2.1') + } + + $.Viewer.prototype.setFilterOptions = function (options) { + if (!this.filterPluginInstance) { + options = options || {} + options.viewer = this + this.filterPluginInstance = new $.FilterPlugin(options) + } else { + setOptions(this.filterPluginInstance, options) + } + } + + /** + * @class FilterPlugin + * @param {Object} options The options + * @param {OpenSeadragon.Viewer} options.viewer The viewer to attach this + * plugin to. + * @param {String} [options.loadMode='async'] Set to sync to have the filters + * applied synchronously. It will only work if the filters are all synchronous. + * Note that depending on how complex the filters are, it may also hang the browser. + * @param {Object[]} options.filters The filters to apply to the images. + * @param {OpenSeadragon.TiledImage[]} options.filters[x].items The tiled images + * on which to apply the filter. + * @param {function|function[]} options.filters[x].processors The processing + * function(s) to apply to the images. The parameters of this function are + * the context to modify and a callback to call upon completion. + */ + $.FilterPlugin = function (options) { + options = options || {} + if (!options.viewer) { + throw new Error('A viewer must be specified.') + } + var self = this + this.viewer = options.viewer + + this.viewer.addHandler('tile-loaded', tileLoadedHandler) + this.viewer.addHandler('tile-drawing', tileDrawingHandler) + + // filterIncrement allows to determine whether a tile contains the + // latest filters results. + this.filterIncrement = 0 + + setOptions(this, options) + + function tileLoadedHandler (event) { + var processors = getFiltersProcessors(self, event.tiledImage) + if (processors.length === 0) { + return + } + var tile = event.tile + var image = event.image + if (image !== null) { + var canvas = window.document.createElement('canvas') + canvas.width = image.width + canvas.height = image.height + var context = canvas.getContext('2d') + context.drawImage(image, 0, 0) + tile._renderedContext = context + var callback = event.getCompletionCallback() + applyFilters(context, processors, callback) + tile._filterIncrement = self.filterIncrement + } + } + + function applyFilters (context, filtersProcessors, callback) { + if (callback) { + var currentIncrement = self.filterIncrement + var callbacks = [] + for (var i = 0; i < filtersProcessors.length - 1; i++) { + (function (i) { + callbacks[i] = function () { + // If the increment has changed, stop the computation + // chain immediately. + if (self.filterIncrement !== currentIncrement) { + return + } + filtersProcessors[i + 1](context, callbacks[i + 1]) + } + })(i) + } + callbacks[filtersProcessors.length - 1] = function () { + // If the increment has changed, do not call the callback. + // (We don't want OSD to draw an outdated tile in the canvas). + if (self.filterIncrement !== currentIncrement) { + return + } + callback() + } + filtersProcessors[0](context, callbacks[0]) + } else { + for (var i = 0; i < filtersProcessors.length; i++) { + filtersProcessors[i](context, function () {}) + } + } + } + + function tileDrawingHandler (event) { + var tile = event.tile + var rendered = event.rendered + if (rendered._filterIncrement === self.filterIncrement) { + return + } + var processors = getFiltersProcessors(self, event.tiledImage) + if (processors.length === 0) { + if (rendered._originalImageData) { + // Restore initial data. + rendered.putImageData(rendered._originalImageData, 0, 0) + delete rendered._originalImageData + } + rendered._filterIncrement = self.filterIncrement + return + } + + if (rendered._originalImageData) { + // The tile has been previously filtered (by another filter), + // restore it first. + rendered.putImageData(rendered._originalImageData, 0, 0) + } else { + rendered._originalImageData = rendered.getImageData( + 0, 0, rendered.canvas.width, rendered.canvas.height) + } + + if (tile._renderedContext) { + if (tile._filterIncrement === self.filterIncrement) { + var imgData = tile._renderedContext.getImageData(0, 0, + tile._renderedContext.canvas.width, + tile._renderedContext.canvas.height) + rendered.putImageData(imgData, 0, 0) + delete tile._renderedContext + delete tile._filterIncrement + rendered._filterIncrement = self.filterIncrement + return + } + delete tile._renderedContext + delete tile._filterIncrement + } + applyFilters(rendered, processors) + rendered._filterIncrement = self.filterIncrement + } + } + + function setOptions (instance, options) { + options = options || {} + var filters = options.filters + instance.filters = !filters ? [] : + $.isArray(filters) ? filters : [filters] + for (var i = 0; i < instance.filters.length; i++) { + var filter = instance.filters[i] + if (!filter.processors) { + throw new Error('Filter processors must be specified.') + } + filter.processors = $.isArray(filter.processors) ? + filter.processors : [filter.processors] + } + instance.filterIncrement++ + + if (options.loadMode === 'sync') { + instance.viewer.forceRedraw() + } else { + var itemsToReset = [] + for (var i = 0; i < instance.filters.length; i++) { + var filter = instance.filters[i] + if (!filter.items) { + itemsToReset = getAllItems(instance.viewer.world) + break + } + if ($.isArray(filter.items)) { + for (var j = 0; j < filter.items.length; j++) { + addItemToReset(filter.items[j], itemsToReset) + } + } else { + addItemToReset(filter.items, itemsToReset) + } + } + for (var i = 0; i < itemsToReset.length; i++) { + itemsToReset[i].reset() + } + } + } + + function addItemToReset (item, itemsToReset) { + if (itemsToReset.indexOf(item) >= 0) { + throw new Error('An item can not have filters ' + + 'assigned multiple times.') + } + itemsToReset.push(item) + } + + function getAllItems (world) { + var result = [] + for (var i = 0; i < world.getItemCount(); i++) { + result.push(world.getItemAt(i)) + } + return result + } + + function getFiltersProcessors (instance, item) { + if (instance.filters.length === 0) { + return [] + } + + var globalProcessors = null + for (var i = 0; i < instance.filters.length; i++) { + var filter = instance.filters[i] + if (!filter.items) { + globalProcessors = filter.processors + } else if (filter.items === item || + $.isArray(filter.items) && filter.items.indexOf(item) >= 0) { + return filter.processors + } + } + return globalProcessors ? globalProcessors : [] + } + + $.Filters = { + THRESHOLDING: function (threshold) { + if (threshold < 0 || threshold > 255) { + throw new Error('Threshold must be between 0 and 255.') + } + return function (context, callback) { + var imgData = context.getImageData( + 0, 0, context.canvas.width, context.canvas.height) + var pixels = imgData.data + for (var i = 0; i < pixels.length; i += 4) { + var r = pixels[i] + var g = pixels[i + 1] + var b = pixels[i + 2] + var v = (r + g + b) / 3 + pixels[i] = pixels[i + 1] = pixels[i + 2] = + v < threshold ? 0 : 255 + } + context.putImageData(imgData, 0, 0) + callback() + } + }, + BRIGHTNESS: function (adjustment) { + if (adjustment < -255 || adjustment > 255) { + throw new Error( + 'Brightness adjustment must be between -255 and 255.') + } + return function (context, callback) { + var imgData = context.getImageData( + 0, 0, context.canvas.width, context.canvas.height) + var pixels = imgData.data + for (var i = 0; i < pixels.length; i += 4) { + pixels[i] += adjustment + pixels[i + 1] += adjustment + pixels[i + 2] += adjustment + } + context.putImageData(imgData, 0, 0) + callback() + } + }, + CONTRAST: function (adjustment) { + if (adjustment < 0) { + throw new Error('Contrast adjustment must be positive.') + } + return function (context, callback) { + var imgData = context.getImageData( + 0, 0, context.canvas.width, context.canvas.height) + var pixels = imgData.data + for (var i = 0; i < pixels.length; i += 4) { + pixels[i] *= adjustment + pixels[i + 1] *= adjustment + pixels[i + 2] *= adjustment + } + context.putImageData(imgData, 0, 0) + callback() + } + }, + GAMMA: function (adjustment) { + if (adjustment < 0) { + throw new Error('Gamma adjustment must be positive.') + } + return function (context, callback) { + var imgData = context.getImageData( + 0, 0, context.canvas.width, context.canvas.height) + var pixels = imgData.data + for (var i = 0; i < pixels.length; i += 4) { + pixels[i] = Math.pow(pixels[i] / 255, adjustment) * 255 + pixels[i + 1] = + Math.pow(pixels[i + 1] / 255, adjustment) * 255 + pixels[i + 2] = + Math.pow(pixels[i + 2] / 255, adjustment) * 255 + } + context.putImageData(imgData, 0, 0) + callback() + } + }, + GREYSCALE: function () { + return function (context, callback) { + var imgData = context.getImageData( + 0, 0, context.canvas.width, context.canvas.height) + var pixels = imgData.data + for (var i = 0; i < pixels.length; i += 4) { + var val = (pixels[i] + pixels[i + 1] + pixels[i + 2]) / 3 + pixels[i] = val + pixels[i + 1] = val + pixels[i + 2] = val + } + context.putImageData(imgData, 0, 0) + callback() + } + }, + INVERT: function () { + return function (context, callback) { + var imgData = context.getImageData( + 0, 0, context.canvas.width, context.canvas.height) + var pixels = imgData.data + for (var i = 0; i < pixels.length; i += 4) { + pixels[i] = 255 - pixels[i] + pixels[i + 1] = 255 - pixels[i + 1] + pixels[i + 2] = 255 - pixels[i + 2] + } + context.putImageData(imgData, 0, 0) + callback() + } + }, + MORPHOLOGICAL_OPERATION: function (kernelSize, comparator) { + if (kernelSize % 2 === 0) { + throw new Error('The kernel size must be an odd number.') + } + var kernelHalfSize = Math.floor(kernelSize / 2) + + if (!comparator) { + throw new Error('A comparator must be defined.') + } + + return function (context, callback) { + var width = context.canvas.width + var height = context.canvas.height + var imgData = context.getImageData(0, 0, width, height) + var originalPixels = context.getImageData(0, 0, width, height) + .data + var offset + + for (var y = 0; y < height; y++) { + for (var x = 0; x < width; x++) { + offset = (y * width + x) * 4 + var r = originalPixels[offset] + var g = originalPixels[offset + 1] + var b = originalPixels[offset + 2] + for (var j = 0; j < kernelSize; j++) { + for (var i = 0; i < kernelSize; i++) { + var pixelX = x + i - kernelHalfSize + var pixelY = y + j - kernelHalfSize + if (pixelX >= 0 && pixelX < width && + pixelY >= 0 && pixelY < height) { + offset = (pixelY * width + pixelX) * 4 + r = comparator(originalPixels[offset], r) + g = comparator( + originalPixels[offset + 1], g) + b = comparator( + originalPixels[offset + 2], b) + } + } + } + imgData.data[offset] = r + imgData.data[offset + 1] = g + imgData.data[offset + 2] = b + } + } + context.putImageData(imgData, 0, 0) + callback() + } + }, + CONVOLUTION: function (kernel) { + if (!$.isArray(kernel)) { + throw new Error('The kernel must be an array.') + } + var kernelSize = Math.sqrt(kernel.length) + if ((kernelSize + 1) % 2 !== 0) { + throw new Error('The kernel must be a square matrix with odd' + + 'width and height.') + } + var kernelHalfSize = (kernelSize - 1) / 2 + + return function (context, callback) { + var width = context.canvas.width + var height = context.canvas.height + var imgData = context.getImageData(0, 0, width, height) + var originalPixels = context.getImageData(0, 0, width, height) + .data + var offset + + for (var y = 0; y < height; y++) { + for (var x = 0; x < width; x++) { + var r = 0 + var g = 0 + var b = 0 + for (var j = 0; j < kernelSize; j++) { + for (var i = 0; i < kernelSize; i++) { + var pixelX = x + i - kernelHalfSize + var pixelY = y + j - kernelHalfSize + if (pixelX >= 0 && pixelX < width && + pixelY >= 0 && pixelY < height) { + offset = (pixelY * width + pixelX) * 4 + var weight = kernel[j * kernelSize + i] + r += originalPixels[offset] * weight + g += originalPixels[offset + 1] * weight + b += originalPixels[offset + 2] * weight + } + } + } + offset = (y * width + x) * 4 + imgData.data[offset] = r + imgData.data[offset + 1] = g + imgData.data[offset + 2] = b + } + } + context.putImageData(imgData, 0, 0) + callback() + } + } + } +}()) diff --git a/js/filteringtools/openseadragon-filtering.js b/js/filteringtools/openseadragon-filtering.js index 124067b1b..dd1c12766 100644 --- a/js/filteringtools/openseadragon-filtering.js +++ b/js/filteringtools/openseadragon-filtering.js @@ -14,434 +14,453 @@ * * @author Antoine Vandecreme */ -;(function () { - 'use strict' +(function() { - var $ = window.OpenSeadragon - if (!$) { - $ = require('openseadragon') + 'use strict'; + + var $ = window.OpenSeadragon; if (!$) { - throw new Error('OpenSeadragon is missing.') + $ = require('openseadragon'); + if (!$) { + throw new Error('OpenSeadragon is missing.'); + } } - } - // Requires OpenSeadragon >=2.1 - if (!$.version || $.version.major < 2 || - $.version.major === 2 && $.version.minor < 1) { - throw new Error( - 'Filtering plugin requires OpenSeadragon version >= 2.1') - } - - $.Viewer.prototype.setFilterOptions = function (options) { - if (!this.filterPluginInstance) { - options = options || {} - options.viewer = this - this.filterPluginInstance = new $.FilterPlugin(options) - } else { - setOptions(this.filterPluginInstance, options) + // Requires OpenSeadragon >=2.1 + if (!$.version || $.version.major < 2 || + $.version.major === 2 && $.version.minor < 1) { + throw new Error( + 'Filtering plugin requires OpenSeadragon version >= 2.1'); } - } - /** - * @class FilterPlugin - * @param {Object} options The options - * @param {OpenSeadragon.Viewer} options.viewer The viewer to attach this - * plugin to. - * @param {String} [options.loadMode='async'] Set to sync to have the filters - * applied synchronously. It will only work if the filters are all synchronous. - * Note that depending on how complex the filters are, it may also hang the browser. - * @param {Object[]} options.filters The filters to apply to the images. - * @param {OpenSeadragon.TiledImage[]} options.filters[x].items The tiled images - * on which to apply the filter. - * @param {function|function[]} options.filters[x].processors The processing - * function(s) to apply to the images. The parameters of this function are - * the context to modify and a callback to call upon completion. - */ - $.FilterPlugin = function (options) { - options = options || {} - if (!options.viewer) { - throw new Error('A viewer must be specified.') - } - var self = this - this.viewer = options.viewer + $.Viewer.prototype.setFilterOptions = function(options) { + if (!this.filterPluginInstance) { + options = options || {}; + options.viewer = this; + this.filterPluginInstance = new $.FilterPlugin(options); + } else { + setOptions(this.filterPluginInstance, options); + } + }; - this.viewer.addHandler('tile-loaded', tileLoadedHandler) - this.viewer.addHandler('tile-drawing', tileDrawingHandler) + /** + * @class FilterPlugin + * @param {Object} options The options + * @param {OpenSeadragon.Viewer} options.viewer The viewer to attach this + * plugin to. + * @param {String} [options.loadMode='async'] Set to sync to have the filters + * applied synchronously. It will only work if the filters are all synchronous. + * Note that depending on how complex the filters are, it may also hang the browser. + * @param {Object[]} options.filters The filters to apply to the images. + * @param {OpenSeadragon.TiledImage[]} options.filters[x].items The tiled images + * on which to apply the filter. + * @param {function|function[]} options.filters[x].processors The processing + * function(s) to apply to the images. The parameters of this function are + * the context to modify and a callback to call upon completion. + */ + $.FilterPlugin = function(options) { + options = options || {}; + if (!options.viewer) { + throw new Error('A viewer must be specified.'); + } + var self = this; + this.viewer = options.viewer; - // filterIncrement allows to determine whether a tile contains the - // latest filters results. - this.filterIncrement = 0 + this.viewer.addHandler('tile-loaded', tileLoadedHandler); + this.viewer.addHandler('tile-drawing', tileDrawingHandler); - setOptions(this, options) + // filterIncrement allows to determine whether a tile contains the + // latest filters results. + this.filterIncrement = 0; - function tileLoadedHandler (event) { - var processors = getFiltersProcessors(self, event.tiledImage) - if (processors.length === 0) { - return - } - var tile = event.tile - var image = event.image - if (image !== null) { - var canvas = window.document.createElement('canvas') - canvas.width = image.width - canvas.height = image.height - var context = canvas.getContext('2d') - context.drawImage(image, 0, 0) - tile._renderedContext = context - var callback = event.getCompletionCallback() - applyFilters(context, processors, callback) - tile._filterIncrement = self.filterIncrement - } - } + setOptions(this, options); - function applyFilters (context, filtersProcessors, callback) { - if (callback) { - var currentIncrement = self.filterIncrement - var callbacks = [] - for (var i = 0; i < filtersProcessors.length - 1; i++) { - (function (i) { - callbacks[i] = function () { - // If the increment has changed, stop the computation - // chain immediately. - if (self.filterIncrement !== currentIncrement) { - return - } - filtersProcessors[i + 1](context, callbacks[i + 1]) + + function tileLoadedHandler(event) { + var processors = getFiltersProcessors(self, event.tiledImage); + if (processors.length === 0) { + return; + } + var tile = event.tile; + var image = event.image; + if (image !== null && typeof(image) != "undefined") { + var canvas = window.document.createElement('canvas'); + canvas.width = image.width; + canvas.height = image.height; + var context = canvas.getContext('2d'); + context.drawImage(image, 0, 0); + tile._renderedContext = context; + var callback = event.getCompletionCallback(); + applyFilters(context, processors, callback); + tile._filterIncrement = self.filterIncrement; } - })(i) - } - callbacks[filtersProcessors.length - 1] = function () { - // If the increment has changed, do not call the callback. - // (We don't want OSD to draw an outdated tile in the canvas). - if (self.filterIncrement !== currentIncrement) { - return - } - callback() - } - filtersProcessors[0](context, callbacks[0]) - } else { - for (var i = 0; i < filtersProcessors.length; i++) { - filtersProcessors[i](context, function () {}) } - } - } - function tileDrawingHandler (event) { - var tile = event.tile - var rendered = event.rendered - if (rendered._filterIncrement === self.filterIncrement) { - return - } - var processors = getFiltersProcessors(self, event.tiledImage) - if (processors.length === 0) { - if (rendered._originalImageData) { - // Restore initial data. - rendered.putImageData(rendered._originalImageData, 0, 0) - delete rendered._originalImageData + + function applyFilters(context, filtersProcessors, callback) { + if (callback) { + var currentIncrement = self.filterIncrement; + var callbacks = []; + for (var i = 0; i < filtersProcessors.length - 1; i++) { + (function(i) { + callbacks[i] = function() { + // If the increment has changed, stop the computation + // chain immediately. + if (self.filterIncrement !== currentIncrement) { + return; + } + filtersProcessors[i + 1](context, callbacks[i + 1]); + }; + })(i); + } + callbacks[filtersProcessors.length - 1] = function() { + // If the increment has changed, do not call the callback. + // (We don't want OSD to draw an outdated tile in the canvas). + if (self.filterIncrement !== currentIncrement) { + return; + } + callback(); + }; + filtersProcessors[0](context, callbacks[0]); + } else { + for (var i = 0; i < filtersProcessors.length; i++) { + filtersProcessors[i](context, function() { + }); + } + } } - rendered._filterIncrement = self.filterIncrement - return - } - if (rendered._originalImageData) { - // The tile has been previously filtered (by another filter), - // restore it first. - rendered.putImageData(rendered._originalImageData, 0, 0) - } else { - rendered._originalImageData = rendered.getImageData( - 0, 0, rendered.canvas.width, rendered.canvas.height) - } + function tileDrawingHandler(event) { + var tile = event.tile; + var rendered = event.rendered; + if (rendered._filterIncrement === self.filterIncrement) { + return; + } + var processors = getFiltersProcessors(self, event.tiledImage); + if (processors.length === 0) { + if (rendered._originalImageData) { + // Restore initial data. + rendered.putImageData(rendered._originalImageData, 0, 0); + delete rendered._originalImageData; + } + rendered._filterIncrement = self.filterIncrement; + return; + } - if (tile._renderedContext) { - if (tile._filterIncrement === self.filterIncrement) { - var imgData = tile._renderedContext.getImageData(0, 0, - tile._renderedContext.canvas.width, - tile._renderedContext.canvas.height) - rendered.putImageData(imgData, 0, 0) - delete tile._renderedContext - delete tile._filterIncrement - rendered._filterIncrement = self.filterIncrement - return - } - delete tile._renderedContext - delete tile._filterIncrement - } - applyFilters(rendered, processors) - rendered._filterIncrement = self.filterIncrement - } - } + if (rendered._originalImageData) { + // The tile has been previously filtered (by another filter), + // restore it first. + rendered.putImageData(rendered._originalImageData, 0, 0); + } else { + rendered._originalImageData = rendered.getImageData( + 0, 0, rendered.canvas.width, rendered.canvas.height); + } - function setOptions (instance, options) { - options = options || {} - var filters = options.filters - instance.filters = !filters ? [] : - $.isArray(filters) ? filters : [filters] - for (var i = 0; i < instance.filters.length; i++) { - var filter = instance.filters[i] - if (!filter.processors) { - throw new Error('Filter processors must be specified.') - } - filter.processors = $.isArray(filter.processors) ? - filter.processors : [filter.processors] - } - instance.filterIncrement++ + if (tile._renderedContext) { + if (tile._filterIncrement === self.filterIncrement) { + var imgData = tile._renderedContext.getImageData(0, 0, + tile._renderedContext.canvas.width, + tile._renderedContext.canvas.height); + rendered.putImageData(imgData, 0, 0); + delete tile._renderedContext; + delete tile._filterIncrement; + rendered._filterIncrement = self.filterIncrement; + return; + } + delete tile._renderedContext; + delete tile._filterIncrement; + } + applyFilters(rendered, processors); + rendered._filterIncrement = self.filterIncrement; + } + }; - if (options.loadMode === 'sync') { - instance.viewer.forceRedraw() - } else { - var itemsToReset = [] - for (var i = 0; i < instance.filters.length; i++) { - var filter = instance.filters[i] - if (!filter.items) { - itemsToReset = getAllItems(instance.viewer.world) - break + function setOptions(instance, options) { + options = options || {}; + var filters = options.filters; + instance.filters = !filters ? [] : + $.isArray(filters) ? filters : [filters]; + for (var i = 0; i < instance.filters.length; i++) { + var filter = instance.filters[i]; + if (!filter.processors) { + throw new Error('Filter processors must be specified.'); + } + filter.processors = $.isArray(filter.processors) ? + filter.processors : [filter.processors]; } - if ($.isArray(filter.items)) { - for (var j = 0; j < filter.items.length; j++) { - addItemToReset(filter.items[j], itemsToReset) - } + instance.filterIncrement++; + + if (options.loadMode === 'sync') { + instance.viewer.forceRedraw(); } else { - addItemToReset(filter.items, itemsToReset) + var itemsToReset = []; + for (var i = 0; i < instance.filters.length; i++) { + var filter = instance.filters[i]; + if (!filter.items) { + itemsToReset = getAllItems(instance.viewer.world); + break; + } + if ($.isArray(filter.items)) { + for (var j = 0; j < filter.items.length; j++) { + addItemToReset(filter.items[j], itemsToReset); + } + } else { + addItemToReset(filter.items, itemsToReset); + } + } + for (var i = 0; i < itemsToReset.length; i++) { + itemsToReset[i].reset(); + } } - } - for (var i = 0; i < itemsToReset.length; i++) { - itemsToReset[i].reset() - } } - } - function addItemToReset (item, itemsToReset) { - if (itemsToReset.indexOf(item) >= 0) { - throw new Error('An item can not have filters ' + - 'assigned multiple times.') + function addItemToReset(item, itemsToReset) { + if (itemsToReset.indexOf(item) >= 0) { + throw new Error('An item can not have filters ' + + 'assigned multiple times.'); + } + itemsToReset.push(item); } - itemsToReset.push(item) - } - function getAllItems (world) { - var result = [] - for (var i = 0; i < world.getItemCount(); i++) { - result.push(world.getItemAt(i)) + function getAllItems(world) { + var result = []; + for (var i = 0; i < world.getItemCount(); i++) { + result.push(world.getItemAt(i)); + } + return result; } - return result - } - function getFiltersProcessors (instance, item) { - if (instance.filters.length === 0) { - return [] - } + function getFiltersProcessors(instance, item) { + if (instance.filters.length === 0) { + return []; + } - var globalProcessors = null - for (var i = 0; i < instance.filters.length; i++) { - var filter = instance.filters[i] - if (!filter.items) { - globalProcessors = filter.processors - } else if (filter.items === item || - $.isArray(filter.items) && filter.items.indexOf(item) >= 0) { - return filter.processors - } + var globalProcessors = null; + for (var i = 0; i < instance.filters.length; i++) { + var filter = instance.filters[i]; + if (!filter.items) { + globalProcessors = filter.processors; + } else if (filter.items === item || + $.isArray(filter.items) && filter.items.indexOf(item) >= 0) { + return filter.processors; + } + } + return globalProcessors ? globalProcessors : []; } - return globalProcessors ? globalProcessors : [] - } - $.Filters = { - THRESHOLDING: function (threshold) { - if (threshold < 0 || threshold > 255) { - throw new Error('Threshold must be between 0 and 255.') - } - return function (context, callback) { - var imgData = context.getImageData( - 0, 0, context.canvas.width, context.canvas.height) - var pixels = imgData.data - for (var i = 0; i < pixels.length; i += 4) { - var r = pixels[i] - var g = pixels[i + 1] - var b = pixels[i + 2] - var v = (r + g + b) / 3 - pixels[i] = pixels[i + 1] = pixels[i + 2] = - v < threshold ? 0 : 255 - } - context.putImageData(imgData, 0, 0) - callback() - } - }, - BRIGHTNESS: function (adjustment) { - if (adjustment < -255 || adjustment > 255) { - throw new Error( - 'Brightness adjustment must be between -255 and 255.') - } - return function (context, callback) { - var imgData = context.getImageData( - 0, 0, context.canvas.width, context.canvas.height) - var pixels = imgData.data - for (var i = 0; i < pixels.length; i += 4) { - pixels[i] += adjustment - pixels[i + 1] += adjustment - pixels[i + 2] += adjustment - } - context.putImageData(imgData, 0, 0) - callback() - } - }, - CONTRAST: function (adjustment) { - if (adjustment < 0) { - throw new Error('Contrast adjustment must be positive.') - } - return function (context, callback) { - var imgData = context.getImageData( - 0, 0, context.canvas.width, context.canvas.height) - var pixels = imgData.data - for (var i = 0; i < pixels.length; i += 4) { - pixels[i] *= adjustment - pixels[i + 1] *= adjustment - pixels[i + 2] *= adjustment - } - context.putImageData(imgData, 0, 0) - callback() - } - }, - GAMMA: function (adjustment) { - if (adjustment < 0) { - throw new Error('Gamma adjustment must be positive.') - } - return function (context, callback) { - var imgData = context.getImageData( - 0, 0, context.canvas.width, context.canvas.height) - var pixels = imgData.data - for (var i = 0; i < pixels.length; i += 4) { - pixels[i] = Math.pow(pixels[i] / 255, adjustment) * 255 - pixels[i + 1] = - Math.pow(pixels[i + 1] / 255, adjustment) * 255 - pixels[i + 2] = - Math.pow(pixels[i + 2] / 255, adjustment) * 255 - } - context.putImageData(imgData, 0, 0) - callback() - } - }, - GREYSCALE: function () { - return function (context, callback) { - var imgData = context.getImageData( - 0, 0, context.canvas.width, context.canvas.height) - var pixels = imgData.data - for (var i = 0; i < pixels.length; i += 4) { - var val = (pixels[i] + pixels[i + 1] + pixels[i + 2]) / 3 - pixels[i] = val - pixels[i + 1] = val - pixels[i + 2] = val - } - context.putImageData(imgData, 0, 0) - callback() - } - }, - INVERT: function () { - return function (context, callback) { - var imgData = context.getImageData( - 0, 0, context.canvas.width, context.canvas.height) - var pixels = imgData.data - for (var i = 0; i < pixels.length; i += 4) { - pixels[i] = 255 - pixels[i] - pixels[i + 1] = 255 - pixels[i + 1] - pixels[i + 2] = 255 - pixels[i + 2] - } - context.putImageData(imgData, 0, 0) - callback() - } - }, - MORPHOLOGICAL_OPERATION: function (kernelSize, comparator) { - if (kernelSize % 2 === 0) { - throw new Error('The kernel size must be an odd number.') - } - var kernelHalfSize = Math.floor(kernelSize / 2) + $.Filters = { + THRESHOLDING: function(threshold) { + if (threshold < 0 || threshold > 255) { + throw new Error('Threshold must be between 0 and 255.'); + } + return function(context, callback) { + var imgData = context.getImageData( + 0, 0, context.canvas.width, context.canvas.height); + var pixels = imgData.data; + for (var i = 0; i < pixels.length; i += 4) { + var r = pixels[i]; + var g = pixels[i + 1]; + var b = pixels[i + 2]; + var v = (r + g + b) / 3; + pixels[i] = pixels[i + 1] = pixels[i + 2] = + v < threshold ? 0 : 255; + } + context.putImageData(imgData, 0, 0); + callback(); + }; + }, + BRIGHTNESS: function(adjustment) { + if (adjustment < -255 || adjustment > 255) { + throw new Error( + 'Brightness adjustment must be between -255 and 255.'); + } + var precomputedBrightness = [] + for (var i = 0; i < 256; i++) { + precomputedBrightness[i] = i + adjustment; + } + return function(context, callback) { + var imgData = context.getImageData( + 0, 0, context.canvas.width, context.canvas.height); + var pixels = imgData.data; + for (var i = 0; i < pixels.length; i += 4) { + pixels[i] = precomputedBrightness[pixels[i]]; + pixels[i + 1] = precomputedBrightness[pixels[i + 1]]; + pixels[i + 2] = precomputedBrightness[pixels[i + 2]]; + } + context.putImageData(imgData, 0, 0); + callback(); + }; + }, + CONTRAST: function(adjustment) { + if (adjustment < 0) { + throw new Error('Contrast adjustment must be positive.'); + } + var precomputedContrast = [] + for (var i = 0; i < 256; i++) { + precomputedContrast[i] = i * adjustment; + } + return function(context, callback) { + var imgData = context.getImageData( + 0, 0, context.canvas.width, context.canvas.height); + var pixels = imgData.data; + for (var i = 0; i < pixels.length; i += 4) { + pixels[i] = precomputedContrast[pixels[i]]; + pixels[i + 1] = precomputedContrast[pixels[i + 1]]; + pixels[i + 2] = precomputedContrast[pixels[i + 2]]; + } + context.putImageData(imgData, 0, 0); + callback(); + }; + }, + GAMMA: function(adjustment) { + if (adjustment < 0) { + throw new Error('Gamma adjustment must be positive.'); + } + var precomputedGamma = [] + for (var i = 0; i < 256; i++) { + precomputedGamma[i] = Math.pow(i / 255, adjustment) * 255; + } + return function(context, callback) { + var imgData = context.getImageData( + 0, 0, context.canvas.width, context.canvas.height); + var pixels = imgData.data; + for (var i = 0; i < pixels.length; i += 4) { + pixels[i] = precomputedGamma[pixels[i]]; + pixels[i + 1] = precomputedGamma[pixels[i + 1]]; + pixels[i + 2] = precomputedGamma[pixels[i + 2]]; + } + context.putImageData(imgData, 0, 0); + callback(); + }; + }, + GREYSCALE: function() { + return function(context, callback) { + var imgData = context.getImageData( + 0, 0, context.canvas.width, context.canvas.height); + var pixels = imgData.data; + for (var i = 0; i < pixels.length; i += 4) { + var val = (pixels[i] + pixels[i + 1] + pixels[i + 2]) / 3; + pixels[i] = val; + pixels[i + 1] = val; + pixels[i + 2] = val; + } + context.putImageData(imgData, 0, 0); + callback(); + }; + }, + INVERT: function () { + var precomputedInvert = [] + for (var i = 0; i < 256; i++) { + precomputedInvert[i] = 255 - i; + } + return function(context, callback) { + var imgData = context.getImageData( + 0, 0, context.canvas.width, context.canvas.height); + var pixels = imgData.data; + for (var i = 0; i < pixels.length; i += 4) { + pixels[i] = precomputedInvert[pixels[i]]; + pixels[i + 1] = precomputedInvert[pixels[i + 1]]; + pixels[i + 2] = precomputedInvert[pixels[i + 2]]; + } + context.putImageData(imgData, 0, 0); + callback(); + }; + }, + MORPHOLOGICAL_OPERATION: function(kernelSize, comparator) { + if (kernelSize % 2 === 0) { + throw new Error('The kernel size must be an odd number.'); + } + var kernelHalfSize = Math.floor(kernelSize / 2); - if (!comparator) { - throw new Error('A comparator must be defined.') - } + if (!comparator) { + throw new Error('A comparator must be defined.'); + } - return function (context, callback) { - var width = context.canvas.width - var height = context.canvas.height - var imgData = context.getImageData(0, 0, width, height) - var originalPixels = context.getImageData(0, 0, width, height) - .data - var offset + return function(context, callback) { + var width = context.canvas.width; + var height = context.canvas.height; + var imgData = context.getImageData(0, 0, width, height); + var originalPixels = context.getImageData(0, 0, width, height) + .data; + var offset; - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - offset = (y * width + x) * 4 - var r = originalPixels[offset] - var g = originalPixels[offset + 1] - var b = originalPixels[offset + 2] - for (var j = 0; j < kernelSize; j++) { - for (var i = 0; i < kernelSize; i++) { - var pixelX = x + i - kernelHalfSize - var pixelY = y + j - kernelHalfSize - if (pixelX >= 0 && pixelX < width && - pixelY >= 0 && pixelY < height) { - offset = (pixelY * width + pixelX) * 4 - r = comparator(originalPixels[offset], r) - g = comparator( - originalPixels[offset + 1], g) - b = comparator( - originalPixels[offset + 2], b) + for (var y = 0; y < height; y++) { + for (var x = 0; x < width; x++) { + offset = (y * width + x) * 4; + var r = originalPixels[offset]; + var g = originalPixels[offset + 1]; + var b = originalPixels[offset + 2]; + for (var j = 0; j < kernelSize; j++) { + for (var i = 0; i < kernelSize; i++) { + var pixelX = x + i - kernelHalfSize; + var pixelY = y + j - kernelHalfSize; + if (pixelX >= 0 && pixelX < width && + pixelY >= 0 && pixelY < height) { + offset = (pixelY * width + pixelX) * 4; + r = comparator(originalPixels[offset], r); + g = comparator( + originalPixels[offset + 1], g); + b = comparator( + originalPixels[offset + 2], b); + } + } + } + imgData.data[offset] = r; + imgData.data[offset + 1] = g; + imgData.data[offset + 2] = b; + } } - } + context.putImageData(imgData, 0, 0); + callback(); + }; + }, + CONVOLUTION: function(kernel) { + if (!$.isArray(kernel)) { + throw new Error('The kernel must be an array.'); } - imgData.data[offset] = r - imgData.data[offset + 1] = g - imgData.data[offset + 2] = b - } - } - context.putImageData(imgData, 0, 0) - callback() - } - }, - CONVOLUTION: function (kernel) { - if (!$.isArray(kernel)) { - throw new Error('The kernel must be an array.') - } - var kernelSize = Math.sqrt(kernel.length) - if ((kernelSize + 1) % 2 !== 0) { - throw new Error('The kernel must be a square matrix with odd' + - 'width and height.') - } - var kernelHalfSize = (kernelSize - 1) / 2 + var kernelSize = Math.sqrt(kernel.length); + if ((kernelSize + 1) % 2 !== 0) { + throw new Error('The kernel must be a square matrix with odd' + + 'width and height.'); + } + var kernelHalfSize = (kernelSize - 1) / 2; - return function (context, callback) { - var width = context.canvas.width - var height = context.canvas.height - var imgData = context.getImageData(0, 0, width, height) - var originalPixels = context.getImageData(0, 0, width, height) - .data - var offset + return function(context, callback) { + var width = context.canvas.width; + var height = context.canvas.height; + var imgData = context.getImageData(0, 0, width, height); + var originalPixels = context.getImageData(0, 0, width, height) + .data; + var offset; - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - var r = 0 - var g = 0 - var b = 0 - for (var j = 0; j < kernelSize; j++) { - for (var i = 0; i < kernelSize; i++) { - var pixelX = x + i - kernelHalfSize - var pixelY = y + j - kernelHalfSize - if (pixelX >= 0 && pixelX < width && - pixelY >= 0 && pixelY < height) { - offset = (pixelY * width + pixelX) * 4 - var weight = kernel[j * kernelSize + i] - r += originalPixels[offset] * weight - g += originalPixels[offset + 1] * weight - b += originalPixels[offset + 2] * weight + for (var y = 0; y < height; y++) { + for (var x = 0; x < width; x++) { + var r = 0; + var g = 0; + var b = 0; + for (var j = 0; j < kernelSize; j++) { + for (var i = 0; i < kernelSize; i++) { + var pixelX = x + i - kernelHalfSize; + var pixelY = y + j - kernelHalfSize; + if (pixelX >= 0 && pixelX < width && + pixelY >= 0 && pixelY < height) { + offset = (pixelY * width + pixelX) * 4; + var weight = kernel[j * kernelSize + i]; + r += originalPixels[offset] * weight; + g += originalPixels[offset + 1] * weight; + b += originalPixels[offset + 2] * weight; + } + } + } + offset = (y * width + x) * 4; + imgData.data[offset] = r; + imgData.data[offset + 1] = g; + imgData.data[offset + 2] = b; + } } - } - } - offset = (y * width + x) * 4 - imgData.data[offset] = r - imgData.data[offset + 1] = g - imgData.data[offset + 2] = b - } + context.putImageData(imgData, 0, 0); + callback(); + }; } - context.putImageData(imgData, 0, 0) - callback() - } - } - } -}()) + }; + +}()); diff --git a/js/imagemetadatatools/osdImageMetadata.js b/js/imagemetadatatools/osdImageMetadata.js index c026be1b6..644b3ff10 100644 --- a/js/imagemetadatatools/osdImageMetadata.js +++ b/js/imagemetadatatools/osdImageMetadata.js @@ -1,15 +1,21 @@ - +/** + * Fetches data and returns an object. + * @param options + */ var OSDImageMetaData = new Class({ - initialize: function(options) { - this.imageId = options.imageId; - this.metaData = null; - this.retrieveImageSize() - this.temp = 2; - }, - retrieveImageSize:function() - { - var jsonRequest = new Request.JSON({url: "api/Data/osdMetadataRetriever.php",async:false, onSuccess: function(e){ - this.metaData=e; - }.bind(this),onFailure:function(e){alert("Failed to get dimension");}.bind(this)}).get({'imageId':this.imageId}); - } + initialize: function (options) { + this.imageId = options.imageId; + this.metaData = null; + this.retrieveImageSize(); + this.temp = 2; + }, + retrieveImageSize: function () { + var jsonRequest = new Request.JSON({ + url: "api/Data/osdMetadataRetriever.php", async: false, onSuccess: function (e) { + this.metaData = e; + }.bind(this), onFailure: function (e) { + alert("Failed to get dimension"); + }.bind(this) + }).get({'imageId': this.imageId}); + } }); diff --git a/js/nouislider.js b/js/nouislider.js new file mode 100644 index 000000000..29ac681c2 --- /dev/null +++ b/js/nouislider.js @@ -0,0 +1,2256 @@ +/*! nouislider - 10.0.0 - 2017-05-28 14:52:48 */ + +(function (factory) { + + if ( typeof define === 'function' && define.amd ) { + + // AMD. Register as an anonymous module. + define([], factory); + + } else if ( typeof exports === 'object' ) { + + // Node/CommonJS + module.exports = factory(); + + } else { + + // Browser globals + window.noUiSlider = factory(); + } + +}(function( ){ + + 'use strict'; + + var VERSION = '10.0.0'; + + + function isValidFormatter ( entry ) { + return typeof entry === 'object' && typeof entry.to === 'function' && typeof entry.from === 'function'; + } + + function removeElement ( el ) { + el.parentElement.removeChild(el); + } + + // Bindable version + function preventDefault ( e ) { + e.preventDefault(); + } + + // Removes duplicates from an array. + function unique ( array ) { + return array.filter(function(a){ + return !this[a] ? this[a] = true : false; + }, {}); + } + + // Round a value to the closest 'to'. + function closest ( value, to ) { + return Math.round(value / to) * to; + } + + // Current position of an element relative to the document. + function offset ( elem, orientation ) { + + var rect = elem.getBoundingClientRect(); + var doc = elem.ownerDocument; + var docElem = doc.documentElement; + var pageOffset = getPageOffset(doc); + + // getBoundingClientRect contains left scroll in Chrome on Android. + // I haven't found a feature detection that proves this. Worst case + // scenario on mis-match: the 'tap' feature on horizontal sliders breaks. + if ( /webkit.*Chrome.*Mobile/i.test(navigator.userAgent) ) { + pageOffset.x = 0; + } + + return orientation ? (rect.top + pageOffset.y - docElem.clientTop) : (rect.left + pageOffset.x - docElem.clientLeft); + } + + // Checks whether a value is numerical. + function isNumeric ( a ) { + return typeof a === 'number' && !isNaN( a ) && isFinite( a ); + } + + // Sets a class and removes it after [duration] ms. + function addClassFor ( element, className, duration ) { + if (duration > 0) { + addClass(element, className); + setTimeout(function(){ + removeClass(element, className); + }, duration); + } + } + + // Limits a value to 0 - 100 + function limit ( a ) { + return Math.max(Math.min(a, 100), 0); + } + + // Wraps a variable as an array, if it isn't one yet. + // Note that an input array is returned by reference! + function asArray ( a ) { + return Array.isArray(a) ? a : [a]; + } + + // Counts decimals + function countDecimals ( numStr ) { + numStr = String(numStr); + var pieces = numStr.split("."); + return pieces.length > 1 ? pieces[1].length : 0; + } + + // http://youmightnotneedjquery.com/#add_class + function addClass ( el, className ) { + if ( el.classList ) { + el.classList.add(className); + } else { + el.className += ' ' + className; + } + } + + // http://youmightnotneedjquery.com/#remove_class + function removeClass ( el, className ) { + if ( el.classList ) { + el.classList.remove(className); + } else { + el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); + } + } + + // https://plainjs.com/javascript/attributes/adding-removing-and-testing-for-classes-9/ + function hasClass ( el, className ) { + return el.classList ? el.classList.contains(className) : new RegExp('\\b' + className + '\\b').test(el.className); + } + + // https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollY#Notes + function getPageOffset ( doc ) { + + var supportPageOffset = window.pageXOffset !== undefined; + var isCSS1Compat = ((doc.compatMode || "") === "CSS1Compat"); + var x = supportPageOffset ? window.pageXOffset : isCSS1Compat ? doc.documentElement.scrollLeft : doc.body.scrollLeft; + var y = supportPageOffset ? window.pageYOffset : isCSS1Compat ? doc.documentElement.scrollTop : doc.body.scrollTop; + + return { + x: x, + y: y + }; + } + + // we provide a function to compute constants instead + // of accessing window.* as soon as the module needs it + // so that we do not compute anything if not needed + function getActions ( ) { + + // Determine the events to bind. IE11 implements pointerEvents without + // a prefix, which breaks compatibility with the IE10 implementation. + return window.navigator.pointerEnabled ? { + start: 'pointerdown', + move: 'pointermove', + end: 'pointerup' + } : window.navigator.msPointerEnabled ? { + start: 'MSPointerDown', + move: 'MSPointerMove', + end: 'MSPointerUp' + } : { + start: 'mousedown touchstart', + move: 'mousemove touchmove', + end: 'mouseup touchend' + }; + } + + // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md + // Issue #785 + function getSupportsPassive ( ) { + + var supportsPassive = false; + + try { + + var opts = Object.defineProperty({}, 'passive', { + get: function() { + supportsPassive = true; + } + }); + + window.addEventListener('test', null, opts); + + } catch (e) {} + + return supportsPassive; + } + + function getSupportsTouchActionNone ( ) { + return window.CSS && CSS.supports && CSS.supports('touch-action', 'none'); + } + + +// Value calculation + + // Determine the size of a sub-range in relation to a full range. + function subRangeRatio ( pa, pb ) { + return (100 / (pb - pa)); + } + + // (percentage) How many percent is this value of this range? + function fromPercentage ( range, value ) { + return (value * 100) / ( range[1] - range[0] ); + } + + // (percentage) Where is this value on this range? + function toPercentage ( range, value ) { + return fromPercentage( range, range[0] < 0 ? + value + Math.abs(range[0]) : + value - range[0] ); + } + + // (value) How much is this percentage on this range? + function isPercentage ( range, value ) { + return ((value * ( range[1] - range[0] )) / 100) + range[0]; + } + + +// Range conversion + + function getJ ( value, arr ) { + + var j = 1; + + while ( value >= arr[j] ){ + j += 1; + } + + return j; + } + + // (percentage) Input a value, find where, on a scale of 0-100, it applies. + function toStepping ( xVal, xPct, value ) { + + if ( value >= xVal.slice(-1)[0] ){ + return 100; + } + + var j = getJ( value, xVal ), va, vb, pa, pb; + + va = xVal[j-1]; + vb = xVal[j]; + pa = xPct[j-1]; + pb = xPct[j]; + + return pa + (toPercentage([va, vb], value) / subRangeRatio (pa, pb)); + } + + // (value) Input a percentage, find where it is on the specified range. + function fromStepping ( xVal, xPct, value ) { + + // There is no range group that fits 100 + if ( value >= 100 ){ + return xVal.slice(-1)[0]; + } + + var j = getJ( value, xPct ), va, vb, pa, pb; + + va = xVal[j-1]; + vb = xVal[j]; + pa = xPct[j-1]; + pb = xPct[j]; + + return isPercentage([va, vb], (value - pa) * subRangeRatio (pa, pb)); + } + + // (percentage) Get the step that applies at a certain value. + function getStep ( xPct, xSteps, snap, value ) { + + if ( value === 100 ) { + return value; + } + + var j = getJ( value, xPct ), a, b; + + // If 'snap' is set, steps are used as fixed points on the slider. + if ( snap ) { + + a = xPct[j-1]; + b = xPct[j]; + + // Find the closest position, a or b. + if ((value - a) > ((b-a)/2)){ + return b; + } + + return a; + } + + if ( !xSteps[j-1] ){ + return value; + } + + return xPct[j-1] + closest( + value - xPct[j-1], + xSteps[j-1] + ); + } + + +// Entry parsing + + function handleEntryPoint ( index, value, that ) { + + var percentage; + + // Wrap numerical input in an array. + if ( typeof value === "number" ) { + value = [value]; + } + + // Reject any invalid input, by testing whether value is an array. + if ( Object.prototype.toString.call( value ) !== '[object Array]' ){ + throw new Error("noUiSlider (" + VERSION + "): 'range' contains invalid value."); + } + + // Covert min/max syntax to 0 and 100. + if ( index === 'min' ) { + percentage = 0; + } else if ( index === 'max' ) { + percentage = 100; + } else { + percentage = parseFloat( index ); + } + + // Check for correct input. + if ( !isNumeric( percentage ) || !isNumeric( value[0] ) ) { + throw new Error("noUiSlider (" + VERSION + "): 'range' value isn't numeric."); + } + + // Store values. + that.xPct.push( percentage ); + that.xVal.push( value[0] ); + + // NaN will evaluate to false too, but to keep + // logging clear, set step explicitly. Make sure + // not to override the 'step' setting with false. + if ( !percentage ) { + if ( !isNaN( value[1] ) ) { + that.xSteps[0] = value[1]; + } + } else { + that.xSteps.push( isNaN(value[1]) ? false : value[1] ); + } + + that.xHighestCompleteStep.push(0); + } + + function handleStepPoint ( i, n, that ) { + + // Ignore 'false' stepping. + if ( !n ) { + return true; + } + + // Factor to range ratio + that.xSteps[i] = fromPercentage([ + that.xVal[i] + ,that.xVal[i+1] + ], n) / subRangeRatio ( + that.xPct[i], + that.xPct[i+1] ); + + var totalSteps = (that.xVal[i+1] - that.xVal[i]) / that.xNumSteps[i]; + var highestStep = Math.ceil(Number(totalSteps.toFixed(3)) - 1); + var step = that.xVal[i] + (that.xNumSteps[i] * highestStep); + + that.xHighestCompleteStep[i] = step; + } + + +// Interface + + function Spectrum ( entry, snap, singleStep ) { + + this.xPct = []; + this.xVal = []; + this.xSteps = [ singleStep || false ]; + this.xNumSteps = [ false ]; + this.xHighestCompleteStep = []; + + this.snap = snap; + + var index, ordered = [ /* [0, 'min'], [1, '50%'], [2, 'max'] */ ]; + + // Map the object keys to an array. + for ( index in entry ) { + if ( entry.hasOwnProperty(index) ) { + ordered.push([entry[index], index]); + } + } + + // Sort all entries by value (numeric sort). + if ( ordered.length && typeof ordered[0][0] === "object" ) { + ordered.sort(function(a, b) { return a[0][0] - b[0][0]; }); + } else { + ordered.sort(function(a, b) { return a[0] - b[0]; }); + } + + + // Convert all entries to subranges. + for ( index = 0; index < ordered.length; index++ ) { + handleEntryPoint(ordered[index][1], ordered[index][0], this); + } + + // Store the actual step values. + // xSteps is sorted in the same order as xPct and xVal. + this.xNumSteps = this.xSteps.slice(0); + + // Convert all numeric steps to the percentage of the subrange they represent. + for ( index = 0; index < this.xNumSteps.length; index++ ) { + handleStepPoint(index, this.xNumSteps[index], this); + } + } + + Spectrum.prototype.getMargin = function ( value ) { + + var step = this.xNumSteps[0]; + + if ( step && ((value / step) % 1) !== 0 ) { + throw new Error("noUiSlider (" + VERSION + "): 'limit', 'margin' and 'padding' must be divisible by step."); + } + + return this.xPct.length === 2 ? fromPercentage(this.xVal, value) : false; + }; + + Spectrum.prototype.toStepping = function ( value ) { + + value = toStepping( this.xVal, this.xPct, value ); + + return value; + }; + + Spectrum.prototype.fromStepping = function ( value ) { + + return fromStepping( this.xVal, this.xPct, value ); + }; + + Spectrum.prototype.getStep = function ( value ) { + + value = getStep(this.xPct, this.xSteps, this.snap, value ); + + return value; + }; + + Spectrum.prototype.getNearbySteps = function ( value ) { + + var j = getJ(value, this.xPct); + + return { + stepBefore: { startValue: this.xVal[j-2], step: this.xNumSteps[j-2], highestStep: this.xHighestCompleteStep[j-2] }, + thisStep: { startValue: this.xVal[j-1], step: this.xNumSteps[j-1], highestStep: this.xHighestCompleteStep[j-1] }, + stepAfter: { startValue: this.xVal[j-0], step: this.xNumSteps[j-0], highestStep: this.xHighestCompleteStep[j-0] } + }; + }; + + Spectrum.prototype.countStepDecimals = function () { + var stepDecimals = this.xNumSteps.map(countDecimals); + return Math.max.apply(null, stepDecimals); + }; + + // Outside testing + Spectrum.prototype.convert = function ( value ) { + return this.getStep(this.toStepping(value)); + }; + +/* Every input option is tested and parsed. This'll prevent + endless validation in internal methods. These tests are + structured with an item for every option available. An + option can be marked as required by setting the 'r' flag. + The testing function is provided with three arguments: + - The provided value for the option; + - A reference to the options object; + - The name for the option; + + The testing function returns false when an error is detected, + or true when everything is OK. It can also modify the option + object, to make sure all values can be correctly looped elsewhere. */ + + var defaultFormatter = { 'to': function( value ){ + return value !== undefined && value.toFixed(2); + }, 'from': Number }; + + function validateFormat ( entry ) { + + // Any object with a to and from method is supported. + if ( isValidFormatter(entry) ) { + return true; + } + + throw new Error("noUiSlider (" + VERSION + "): 'format' requires 'to' and 'from' methods."); + } + + function testStep ( parsed, entry ) { + + if ( !isNumeric( entry ) ) { + throw new Error("noUiSlider (" + VERSION + "): 'step' is not numeric."); + } + + // The step option can still be used to set stepping + // for linear sliders. Overwritten if set in 'range'. + parsed.singleStep = entry; + } + + function testRange ( parsed, entry ) { + + // Filter incorrect input. + if ( typeof entry !== 'object' || Array.isArray(entry) ) { + throw new Error("noUiSlider (" + VERSION + "): 'range' is not an object."); + } + + // Catch missing start or end. + if ( entry.min === undefined || entry.max === undefined ) { + throw new Error("noUiSlider (" + VERSION + "): Missing 'min' or 'max' in 'range'."); + } + + // Catch equal start or end. + if ( entry.min === entry.max ) { + throw new Error("noUiSlider (" + VERSION + "): 'range' 'min' and 'max' cannot be equal."); + } + + parsed.spectrum = new Spectrum(entry, parsed.snap, parsed.singleStep); + } + + function testStart ( parsed, entry ) { + + entry = asArray(entry); + + // Validate input. Values aren't tested, as the public .val method + // will always provide a valid location. + if ( !Array.isArray( entry ) || !entry.length ) { + throw new Error("noUiSlider (" + VERSION + "): 'start' option is incorrect."); + } + + // Store the number of handles. + parsed.handles = entry.length; + + // When the slider is initialized, the .val method will + // be called with the start options. + parsed.start = entry; + } + + function testSnap ( parsed, entry ) { + + // Enforce 100% stepping within subranges. + parsed.snap = entry; + + if ( typeof entry !== 'boolean' ){ + throw new Error("noUiSlider (" + VERSION + "): 'snap' option must be a boolean."); + } + } + + function testAnimate ( parsed, entry ) { + + // Enforce 100% stepping within subranges. + parsed.animate = entry; + + if ( typeof entry !== 'boolean' ){ + throw new Error("noUiSlider (" + VERSION + "): 'animate' option must be a boolean."); + } + } + + function testAnimationDuration ( parsed, entry ) { + + parsed.animationDuration = entry; + + if ( typeof entry !== 'number' ){ + throw new Error("noUiSlider (" + VERSION + "): 'animationDuration' option must be a number."); + } + } + + function testConnect ( parsed, entry ) { + + var connect = [false]; + var i; + + // Map legacy options + if ( entry === 'lower' ) { + entry = [true, false]; + } + + else if ( entry === 'upper' ) { + entry = [false, true]; + } + + // Handle boolean options + if ( entry === true || entry === false ) { + + for ( i = 1; i < parsed.handles; i++ ) { + connect.push(entry); + } + + connect.push(false); + } + + // Reject invalid input + else if ( !Array.isArray( entry ) || !entry.length || entry.length !== parsed.handles + 1 ) { + throw new Error("noUiSlider (" + VERSION + "): 'connect' option doesn't match handle count."); + } + + else { + connect = entry; + } + + parsed.connect = connect; + } + + function testOrientation ( parsed, entry ) { + + // Set orientation to an a numerical value for easy + // array selection. + switch ( entry ){ + case 'horizontal': + parsed.ort = 0; + break; + case 'vertical': + parsed.ort = 1; + break; + default: + throw new Error("noUiSlider (" + VERSION + "): 'orientation' option is invalid."); + } + } + + function testMargin ( parsed, entry ) { + + if ( !isNumeric(entry) ){ + throw new Error("noUiSlider (" + VERSION + "): 'margin' option must be numeric."); + } + + // Issue #582 + if ( entry === 0 ) { + return; + } + + parsed.margin = parsed.spectrum.getMargin(entry); + + if ( !parsed.margin ) { + throw new Error("noUiSlider (" + VERSION + "): 'margin' option is only supported on linear sliders."); + } + } + + function testLimit ( parsed, entry ) { + + if ( !isNumeric(entry) ){ + throw new Error("noUiSlider (" + VERSION + "): 'limit' option must be numeric."); + } + + parsed.limit = parsed.spectrum.getMargin(entry); + + if ( !parsed.limit || parsed.handles < 2 ) { + throw new Error("noUiSlider (" + VERSION + "): 'limit' option is only supported on linear sliders with 2 or more handles."); + } + } + + function testPadding ( parsed, entry ) { + + if ( !isNumeric(entry) ){ + throw new Error("noUiSlider (" + VERSION + "): 'padding' option must be numeric."); + } + + if ( entry === 0 ) { + return; + } + + parsed.padding = parsed.spectrum.getMargin(entry); + + if ( !parsed.padding ) { + throw new Error("noUiSlider (" + VERSION + "): 'padding' option is only supported on linear sliders."); + } + + if ( parsed.padding < 0 ) { + throw new Error("noUiSlider (" + VERSION + "): 'padding' option must be a positive number."); + } + + if ( parsed.padding >= 50 ) { + throw new Error("noUiSlider (" + VERSION + "): 'padding' option must be less than half the range."); + } + } + + function testDirection ( parsed, entry ) { + + // Set direction as a numerical value for easy parsing. + // Invert connection for RTL sliders, so that the proper + // handles get the connect/background classes. + switch ( entry ) { + case 'ltr': + parsed.dir = 0; + break; + case 'rtl': + parsed.dir = 1; + break; + default: + throw new Error("noUiSlider (" + VERSION + "): 'direction' option was not recognized."); + } + } + + function testBehaviour ( parsed, entry ) { + + // Make sure the input is a string. + if ( typeof entry !== 'string' ) { + throw new Error("noUiSlider (" + VERSION + "): 'behaviour' must be a string containing options."); + } + + // Check if the string contains any keywords. + // None are required. + var tap = entry.indexOf('tap') >= 0; + var drag = entry.indexOf('drag') >= 0; + var fixed = entry.indexOf('fixed') >= 0; + var snap = entry.indexOf('snap') >= 0; + var hover = entry.indexOf('hover') >= 0; + + if ( fixed ) { + + if ( parsed.handles !== 2 ) { + throw new Error("noUiSlider (" + VERSION + "): 'fixed' behaviour must be used with 2 handles"); + } + + // Use margin to enforce fixed state + testMargin(parsed, parsed.start[1] - parsed.start[0]); + } + + parsed.events = { + tap: tap || snap, + drag: drag, + fixed: fixed, + snap: snap, + hover: hover + }; + } + + function testTooltips ( parsed, entry ) { + + if ( entry === false ) { + return; + } + + else if ( entry === true ) { + + parsed.tooltips = []; + + for ( var i = 0; i < parsed.handles; i++ ) { + parsed.tooltips.push(true); + } + } + + else { + + parsed.tooltips = asArray(entry); + + if ( parsed.tooltips.length !== parsed.handles ) { + throw new Error("noUiSlider (" + VERSION + "): must pass a formatter for all handles."); + } + + parsed.tooltips.forEach(function(formatter){ + if ( typeof formatter !== 'boolean' && (typeof formatter !== 'object' || typeof formatter.to !== 'function') ) { + throw new Error("noUiSlider (" + VERSION + "): 'tooltips' must be passed a formatter or 'false'."); + } + }); + } + } + + function testAriaFormat ( parsed, entry ) { + parsed.ariaFormat = entry; + validateFormat(entry); + } + + function testFormat ( parsed, entry ) { + parsed.format = entry; + validateFormat(entry); + } + + function testCssPrefix ( parsed, entry ) { + + if ( entry !== undefined && typeof entry !== 'string' && entry !== false ) { + throw new Error("noUiSlider (" + VERSION + "): 'cssPrefix' must be a string or `false`."); + } + + parsed.cssPrefix = entry; + } + + function testCssClasses ( parsed, entry ) { + + if ( entry !== undefined && typeof entry !== 'object' ) { + throw new Error("noUiSlider (" + VERSION + "): 'cssClasses' must be an object."); + } + + if ( typeof parsed.cssPrefix === 'string' ) { + parsed.cssClasses = {}; + + for ( var key in entry ) { + if ( !entry.hasOwnProperty(key) ) { continue; } + + parsed.cssClasses[key] = parsed.cssPrefix + entry[key]; + } + } else { + parsed.cssClasses = entry; + } + } + + function testUseRaf ( parsed, entry ) { + if ( entry === true || entry === false ) { + parsed.useRequestAnimationFrame = entry; + } else { + throw new Error("noUiSlider (" + VERSION + "): 'useRequestAnimationFrame' option should be true (default) or false."); + } + } + + // Test all developer settings and parse to assumption-safe values. + function testOptions ( options ) { + + // To prove a fix for #537, freeze options here. + // If the object is modified, an error will be thrown. + // Object.freeze(options); + + var parsed = { + margin: 0, + limit: 0, + padding: 0, + animate: true, + animationDuration: 300, + ariaFormat: defaultFormatter, + format: defaultFormatter + }; + + // Tests are executed in the order they are presented here. + var tests = { + 'step': { r: false, t: testStep }, + 'start': { r: true, t: testStart }, + 'connect': { r: true, t: testConnect }, + 'direction': { r: true, t: testDirection }, + 'snap': { r: false, t: testSnap }, + 'animate': { r: false, t: testAnimate }, + 'animationDuration': { r: false, t: testAnimationDuration }, + 'range': { r: true, t: testRange }, + 'orientation': { r: false, t: testOrientation }, + 'margin': { r: false, t: testMargin }, + 'limit': { r: false, t: testLimit }, + 'padding': { r: false, t: testPadding }, + 'behaviour': { r: true, t: testBehaviour }, + 'ariaFormat': { r: false, t: testAriaFormat }, + 'format': { r: false, t: testFormat }, + 'tooltips': { r: false, t: testTooltips }, + 'cssPrefix': { r: false, t: testCssPrefix }, + 'cssClasses': { r: false, t: testCssClasses }, + 'useRequestAnimationFrame': { r: false, t: testUseRaf } + }; + + var defaults = { + 'connect': false, + 'direction': 'ltr', + 'behaviour': 'tap', + 'orientation': 'horizontal', + 'cssPrefix' : 'noUi-', + 'cssClasses': { + target: 'target', + base: 'base', + origin: 'origin', + handle: 'handle', + handleLower: 'handle-lower', + handleUpper: 'handle-upper', + horizontal: 'horizontal', + vertical: 'vertical', + background: 'background', + connect: 'connect', + ltr: 'ltr', + rtl: 'rtl', + draggable: 'draggable', + drag: 'state-drag', + tap: 'state-tap', + active: 'active', + tooltip: 'tooltip', + pips: 'pips', + pipsHorizontal: 'pips-horizontal', + pipsVertical: 'pips-vertical', + marker: 'marker', + markerHorizontal: 'marker-horizontal', + markerVertical: 'marker-vertical', + markerNormal: 'marker-normal', + markerLarge: 'marker-large', + markerSub: 'marker-sub', + value: 'value', + valueHorizontal: 'value-horizontal', + valueVertical: 'value-vertical', + valueNormal: 'value-normal', + valueLarge: 'value-large', + valueSub: 'value-sub' + }, + 'useRequestAnimationFrame': true + }; + + // AriaFormat defaults to regular format, if any. + if ( options.format && !options.ariaFormat ) { + options.ariaFormat = options.format; + } + + // Run all options through a testing mechanism to ensure correct + // input. It should be noted that options might get modified to + // be handled properly. E.g. wrapping integers in arrays. + Object.keys(tests).forEach(function( name ){ + + // If the option isn't set, but it is required, throw an error. + if ( options[name] === undefined && defaults[name] === undefined ) { + + if ( tests[name].r ) { + throw new Error("noUiSlider (" + VERSION + "): '" + name + "' is required."); + } + + return true; + } + + tests[name].t( parsed, options[name] === undefined ? defaults[name] : options[name] ); + }); + + // Forward pips options + parsed.pips = options.pips; + + var styles = [['left', 'top'], ['right', 'bottom']]; + + // Pre-define the styles. + parsed.style = styles[parsed.dir][parsed.ort]; + parsed.styleOposite = styles[parsed.dir?0:1][parsed.ort]; + + return parsed; + } + + +function closure ( target, options, originalOptions ){ + + var actions = getActions(); + var supportsTouchActionNone = getSupportsTouchActionNone(); + var supportsPassive = supportsTouchActionNone && getSupportsPassive(); + + // All variables local to 'closure' are prefixed with 'scope_' + var scope_Target = target; + var scope_Locations = []; + var scope_Base; + var scope_Handles; + var scope_HandleNumbers = []; + var scope_ActiveHandle = false; + var scope_Connects; + var scope_Spectrum = options.spectrum; + var scope_Values = []; + var scope_Events = {}; + var scope_Self; + var scope_Pips; + var scope_Listeners = null; + var scope_Document = target.ownerDocument; + var scope_DocumentElement = scope_Document.documentElement; + var scope_Body = scope_Document.body; + + + // Creates a node, adds it to target, returns the new node. + function addNodeTo ( target, className ) { + + var div = scope_Document.createElement('div'); + + if ( className ) { + addClass(div, className); + } + + target.appendChild(div); + + return div; + } + + // Append a origin to the base + function addOrigin ( base, handleNumber ) { + + var origin = addNodeTo(base, options.cssClasses.origin); + var handle = addNodeTo(origin, options.cssClasses.handle); + + handle.setAttribute('data-handle', handleNumber); + + // https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex + // 0 = focusable and reachable + handle.setAttribute('tabindex', '0'); + handle.setAttribute('role', 'slider'); + handle.setAttribute('aria-orientation', options.ort ? 'vertical' : 'horizontal'); + + if ( handleNumber === 0 ) { + addClass(handle, options.cssClasses.handleLower); + } + + else if ( handleNumber === options.handles - 1 ) { + addClass(handle, options.cssClasses.handleUpper); + } + + return origin; + } + + // Insert nodes for connect elements + function addConnect ( base, add ) { + + if ( !add ) { + return false; + } + + return addNodeTo(base, options.cssClasses.connect); + } + + // Add handles to the slider base. + function addElements ( connectOptions, base ) { + + scope_Handles = []; + scope_Connects = []; + + scope_Connects.push(addConnect(base, connectOptions[0])); + + // [::::O====O====O====] + // connectOptions = [0, 1, 1, 1] + + for ( var i = 0; i < options.handles; i++ ) { + // Keep a list of all added handles. + scope_Handles.push(addOrigin(base, i)); + scope_HandleNumbers[i] = i; + scope_Connects.push(addConnect(base, connectOptions[i + 1])); + } + } + + // Initialize a single slider. + function addSlider ( target ) { + + // Apply classes and data to the target. + addClass(target, options.cssClasses.target); + + if ( options.dir === 0 ) { + addClass(target, options.cssClasses.ltr); + } else { + addClass(target, options.cssClasses.rtl); + } + + if ( options.ort === 0 ) { + addClass(target, options.cssClasses.horizontal); + } else { + addClass(target, options.cssClasses.vertical); + } + + scope_Base = addNodeTo(target, options.cssClasses.base); + } + + + function addTooltip ( handle, handleNumber ) { + + if ( !options.tooltips[handleNumber] ) { + return false; + } + + return addNodeTo(handle.firstChild, options.cssClasses.tooltip); + } + + // The tooltips option is a shorthand for using the 'update' event. + function tooltips ( ) { + + // Tooltips are added with options.tooltips in original order. + var tips = scope_Handles.map(addTooltip); + + bindEvent('update', function(values, handleNumber, unencoded) { + + if ( !tips[handleNumber] ) { + return; + } + + var formattedValue = values[handleNumber]; + + if ( options.tooltips[handleNumber] !== true ) { + formattedValue = options.tooltips[handleNumber].to(unencoded[handleNumber]); + } + + tips[handleNumber].innerHTML = formattedValue; + }); + } + + + function aria ( ) { + + bindEvent('update', function ( values, handleNumber, unencoded, tap, positions ) { + + // Update Aria Values for all handles, as a change in one changes min and max values for the next. + scope_HandleNumbers.forEach(function( handleNumber ){ + + var handle = scope_Handles[handleNumber]; + + var min = checkHandlePosition(scope_Locations, handleNumber, 0, true, true, true); + var max = checkHandlePosition(scope_Locations, handleNumber, 100, true, true, true); + + var now = positions[handleNumber]; + var text = options.ariaFormat.to(unencoded[handleNumber]); + + handle.children[0].setAttribute('aria-valuemin', min.toFixed(1)); + handle.children[0].setAttribute('aria-valuemax', max.toFixed(1)); + handle.children[0].setAttribute('aria-valuenow', now.toFixed(1)); + handle.children[0].setAttribute('aria-valuetext', text); + }); + }); + } + + + function getGroup ( mode, values, stepped ) { + + // Use the range. + if ( mode === 'range' || mode === 'steps' ) { + return scope_Spectrum.xVal; + } + + if ( mode === 'count' ) { + + if ( !values ) { + throw new Error("noUiSlider (" + VERSION + "): 'values' required for mode 'count'."); + } + + // Divide 0 - 100 in 'count' parts. + var spread = ( 100 / (values - 1) ); + var v; + var i = 0; + + values = []; + + // List these parts and have them handled as 'positions'. + while ( (v = i++ * spread) <= 100 ) { + values.push(v); + } + + mode = 'positions'; + } + + if ( mode === 'positions' ) { + + // Map all percentages to on-range values. + return values.map(function( value ){ + return scope_Spectrum.fromStepping( stepped ? scope_Spectrum.getStep( value ) : value ); + }); + } + + if ( mode === 'values' ) { + + // If the value must be stepped, it needs to be converted to a percentage first. + if ( stepped ) { + + return values.map(function( value ){ + + // Convert to percentage, apply step, return to value. + return scope_Spectrum.fromStepping( scope_Spectrum.getStep( scope_Spectrum.toStepping( value ) ) ); + }); + + } + + // Otherwise, we can simply use the values. + return values; + } + } + + function generateSpread ( density, mode, group ) { + + function safeIncrement(value, increment) { + // Avoid floating point variance by dropping the smallest decimal places. + return (value + increment).toFixed(7) / 1; + } + + var indexes = {}; + var firstInRange = scope_Spectrum.xVal[0]; + var lastInRange = scope_Spectrum.xVal[scope_Spectrum.xVal.length-1]; + var ignoreFirst = false; + var ignoreLast = false; + var prevPct = 0; + + // Create a copy of the group, sort it and filter away all duplicates. + group = unique(group.slice().sort(function(a, b){ return a - b; })); + + // Make sure the range starts with the first element. + if ( group[0] !== firstInRange ) { + group.unshift(firstInRange); + ignoreFirst = true; + } + + // Likewise for the last one. + if ( group[group.length - 1] !== lastInRange ) { + group.push(lastInRange); + ignoreLast = true; + } + + group.forEach(function ( current, index ) { + + // Get the current step and the lower + upper positions. + var step; + var i; + var q; + var low = current; + var high = group[index+1]; + var newPct; + var pctDifference; + var pctPos; + var type; + var steps; + var realSteps; + var stepsize; + + // When using 'steps' mode, use the provided steps. + // Otherwise, we'll step on to the next subrange. + if ( mode === 'steps' ) { + step = scope_Spectrum.xNumSteps[ index ]; + } + + // Default to a 'full' step. + if ( !step ) { + step = high-low; + } + + // Low can be 0, so test for false. If high is undefined, + // we are at the last subrange. Index 0 is already handled. + if ( low === false || high === undefined ) { + return; + } + + // Make sure step isn't 0, which would cause an infinite loop (#654) + step = Math.max(step, 0.0000001); + + // Find all steps in the subrange. + for ( i = low; i <= high; i = safeIncrement(i, step) ) { + + // Get the percentage value for the current step, + // calculate the size for the subrange. + newPct = scope_Spectrum.toStepping( i ); + pctDifference = newPct - prevPct; + + steps = pctDifference / density; + realSteps = Math.round(steps); + + // This ratio represents the ammount of percentage-space a point indicates. + // For a density 1 the points/percentage = 1. For density 2, that percentage needs to be re-devided. + // Round the percentage offset to an even number, then divide by two + // to spread the offset on both sides of the range. + stepsize = pctDifference/realSteps; + + // Divide all points evenly, adding the correct number to this subrange. + // Run up to <= so that 100% gets a point, event if ignoreLast is set. + for ( q = 1; q <= realSteps; q += 1 ) { + + // The ratio between the rounded value and the actual size might be ~1% off. + // Correct the percentage offset by the number of points + // per subrange. density = 1 will result in 100 points on the + // full range, 2 for 50, 4 for 25, etc. + pctPos = prevPct + ( q * stepsize ); + indexes[pctPos.toFixed(5)] = ['x', 0]; + } + + // Determine the point type. + type = (group.indexOf(i) > -1) ? 1 : ( mode === 'steps' ? 2 : 0 ); + + // Enforce the 'ignoreFirst' option by overwriting the type for 0. + if ( !index && ignoreFirst ) { + type = 0; + } + + if ( !(i === high && ignoreLast)) { + // Mark the 'type' of this point. 0 = plain, 1 = real value, 2 = step value. + indexes[newPct.toFixed(5)] = [i, type]; + } + + // Update the percentage count. + prevPct = newPct; + } + }); + + return indexes; + } + + function addMarking ( spread, filterFunc, formatter ) { + + var element = scope_Document.createElement('div'); + + var valueSizeClasses = [ + options.cssClasses.valueNormal, + options.cssClasses.valueLarge, + options.cssClasses.valueSub + ]; + var markerSizeClasses = [ + options.cssClasses.markerNormal, + options.cssClasses.markerLarge, + options.cssClasses.markerSub + ]; + var valueOrientationClasses = [ + options.cssClasses.valueHorizontal, + options.cssClasses.valueVertical + ]; + var markerOrientationClasses = [ + options.cssClasses.markerHorizontal, + options.cssClasses.markerVertical + ]; + + addClass(element, options.cssClasses.pips); + addClass(element, options.ort === 0 ? options.cssClasses.pipsHorizontal : options.cssClasses.pipsVertical); + + function getClasses( type, source ){ + var a = source === options.cssClasses.value; + var orientationClasses = a ? valueOrientationClasses : markerOrientationClasses; + var sizeClasses = a ? valueSizeClasses : markerSizeClasses; + + return source + ' ' + orientationClasses[options.ort] + ' ' + sizeClasses[type]; + } + + function addSpread ( offset, values ){ + + // Apply the filter function, if it is set. + values[1] = (values[1] && filterFunc) ? filterFunc(values[0], values[1]) : values[1]; + + // Add a marker for every point + var node = addNodeTo(element, false); + node.className = getClasses(values[1], options.cssClasses.marker); + node.style[options.style] = offset + '%'; + + // Values are only appended for points marked '1' or '2'. + if ( values[1] ) { + node = addNodeTo(element, false); + node.className = getClasses(values[1], options.cssClasses.value); + node.style[options.style] = offset + '%'; + node.innerText = formatter.to(values[0]); + } + } + + // Append all points. + Object.keys(spread).forEach(function(a){ + addSpread(a, spread[a]); + }); + + return element; + } + + function removePips ( ) { + if ( scope_Pips ) { + removeElement(scope_Pips); + scope_Pips = null; + } + } + + function pips ( grid ) { + + // Fix #669 + removePips(); + + var mode = grid.mode; + var density = grid.density || 1; + var filter = grid.filter || false; + var values = grid.values || false; + var stepped = grid.stepped || false; + var group = getGroup( mode, values, stepped ); + var spread = generateSpread( density, mode, group ); + var format = grid.format || { + to: Math.round + }; + + scope_Pips = scope_Target.appendChild(addMarking( + spread, + filter, + format + )); + + return scope_Pips; + } + + + // Shorthand for base dimensions. + function baseSize ( ) { + var rect = scope_Base.getBoundingClientRect(), alt = 'offset' + ['Width', 'Height'][options.ort]; + return options.ort === 0 ? (rect.width||scope_Base[alt]) : (rect.height||scope_Base[alt]); + } + + // Handler for attaching events trough a proxy. + function attachEvent ( events, element, callback, data ) { + + // This function can be used to 'filter' events to the slider. + // element is a node, not a nodeList + + var method = function ( e ){ + + if ( scope_Target.hasAttribute('disabled') ) { + return false; + } + + // Stop if an active 'tap' transition is taking place. + if ( hasClass(scope_Target, options.cssClasses.tap) ) { + return false; + } + + e = fixEvent(e, data.pageOffset); + + // Handle reject of multitouch + if ( !e ) { + return false; + } + + // Ignore right or middle clicks on start #454 + if ( events === actions.start && e.buttons !== undefined && e.buttons > 1 ) { + return false; + } + + // Ignore right or middle clicks on start #454 + if ( data.hover && e.buttons ) { + return false; + } + + // 'supportsPassive' is only true if a browser also supports touch-action: none in CSS. + // iOS safari does not, so it doesn't get to benefit from passive scrolling. iOS does support + // touch-action: manipulation, but that allows panning, which breaks + // sliders after zooming/on non-responsive pages. + // See: https://bugs.webkit.org/show_bug.cgi?id=133112 + if ( !supportsPassive ) { + e.preventDefault(); + } + + e.calcPoint = e.points[ options.ort ]; + + // Call the event handler with the event [ and additional data ]. + callback ( e, data ); + }; + + var methods = []; + + // Bind a closure on the target for every event type. + events.split(' ').forEach(function( eventName ){ + element.addEventListener(eventName, method, supportsPassive ? { passive: true } : false); + methods.push([eventName, method]); + }); + + return methods; + } + + // Provide a clean event with standardized offset values. + function fixEvent ( e, pageOffset ) { + + // Filter the event to register the type, which can be + // touch, mouse or pointer. Offset changes need to be + // made on an event specific basis. + var touch = e.type.indexOf('touch') === 0; + var mouse = e.type.indexOf('mouse') === 0; + var pointer = e.type.indexOf('pointer') === 0; + + var x; + var y; + + // IE10 implemented pointer events with a prefix; + if ( e.type.indexOf('MSPointer') === 0 ) { + pointer = true; + } + + if ( touch ) { + + // Fix bug when user touches with two or more fingers on mobile devices. + // It's useful when you have two or more sliders on one page, + // that can be touched simultaneously. + // #649, #663, #668 + if ( e.touches.length > 1 ) { + return false; + } + + // noUiSlider supports one movement at a time, + // so we can select the first 'changedTouch'. + x = e.changedTouches[0].pageX; + y = e.changedTouches[0].pageY; + } + + pageOffset = pageOffset || getPageOffset(scope_Document); + + if ( mouse || pointer ) { + x = e.clientX + pageOffset.x; + y = e.clientY + pageOffset.y; + } + + e.pageOffset = pageOffset; + e.points = [x, y]; + e.cursor = mouse || pointer; // Fix #435 + + return e; + } + + // Translate a coordinate in the document to a percentage on the slider + function calcPointToPercentage ( calcPoint ) { + var location = calcPoint - offset(scope_Base, options.ort); + var proposal = ( location * 100 ) / baseSize(); + return options.dir ? 100 - proposal : proposal; + } + + // Find handle closest to a certain percentage on the slider + function getClosestHandle ( proposal ) { + + var closest = 100; + var handleNumber = false; + + scope_Handles.forEach(function(handle, index){ + + // Disabled handles are ignored + if ( handle.hasAttribute('disabled') ) { + return; + } + + var pos = Math.abs(scope_Locations[index] - proposal); + + if ( pos < closest ) { + handleNumber = index; + closest = pos; + } + }); + + return handleNumber; + } + + // Moves handle(s) by a percentage + // (bool, % to move, [% where handle started, ...], [index in scope_Handles, ...]) + function moveHandles ( upward, proposal, locations, handleNumbers ) { + + var proposals = locations.slice(); + + var b = [!upward, upward]; + var f = [upward, !upward]; + + // Copy handleNumbers so we don't change the dataset + handleNumbers = handleNumbers.slice(); + + // Check to see which handle is 'leading'. + // If that one can't move the second can't either. + if ( upward ) { + handleNumbers.reverse(); + } + + // Step 1: get the maximum percentage that any of the handles can move + if ( handleNumbers.length > 1 ) { + + handleNumbers.forEach(function(handleNumber, o) { + + var to = checkHandlePosition(proposals, handleNumber, proposals[handleNumber] + proposal, b[o], f[o], false); + + // Stop if one of the handles can't move. + if ( to === false ) { + proposal = 0; + } else { + proposal = to - proposals[handleNumber]; + proposals[handleNumber] = to; + } + }); + } + + // If using one handle, check backward AND forward + else { + b = f = [true]; + } + + var state = false; + + // Step 2: Try to set the handles with the found percentage + handleNumbers.forEach(function(handleNumber, o) { + state = setHandle(handleNumber, locations[handleNumber] + proposal, b[o], f[o]) || state; + }); + + // Step 3: If a handle moved, fire events + if ( state ) { + handleNumbers.forEach(function(handleNumber){ + fireEvent('update', handleNumber); + fireEvent('slide', handleNumber); + }); + } + } + + // External event handling + function fireEvent ( eventName, handleNumber, tap ) { + + Object.keys(scope_Events).forEach(function( targetEvent ) { + + var eventType = targetEvent.split('.')[0]; + + if ( eventName === eventType ) { + scope_Events[targetEvent].forEach(function( callback ) { + + callback.call( + // Use the slider public API as the scope ('this') + scope_Self, + // Return values as array, so arg_1[arg_2] is always valid. + scope_Values.map(options.format.to), + // Handle index, 0 or 1 + handleNumber, + // Unformatted slider values + scope_Values.slice(), + // Event is fired by tap, true or false + tap || false, + // Left offset of the handle, in relation to the slider + scope_Locations.slice() + ); + }); + } + }); + } + + + // Fire 'end' when a mouse or pen leaves the document. + function documentLeave ( event, data ) { + if ( event.type === "mouseout" && event.target.nodeName === "HTML" && event.relatedTarget === null ){ + eventEnd (event, data); + } + } + + // Handle movement on document for handle and range drag. + function eventMove ( event, data ) { + + // Fix #498 + // Check value of .buttons in 'start' to work around a bug in IE10 mobile (data.buttonsProperty). + // https://connect.microsoft.com/IE/feedback/details/927005/mobile-ie10-windows-phone-buttons-property-of-pointermove-event-always-zero + // IE9 has .buttons and .which zero on mousemove. + // Firefox breaks the spec MDN defines. + if ( navigator.appVersion.indexOf("MSIE 9") === -1 && event.buttons === 0 && data.buttonsProperty !== 0 ) { + return eventEnd(event, data); + } + + // Check if we are moving up or down + var movement = (options.dir ? -1 : 1) * (event.calcPoint - data.startCalcPoint); + + // Convert the movement into a percentage of the slider width/height + var proposal = (movement * 100) / data.baseSize; + + moveHandles(movement > 0, proposal, data.locations, data.handleNumbers); + } + + // Unbind move events on document, call callbacks. + function eventEnd ( event, data ) { + + // The handle is no longer active, so remove the class. + if ( scope_ActiveHandle ) { + removeClass(scope_ActiveHandle, options.cssClasses.active); + scope_ActiveHandle = false; + } + + // Remove cursor styles and text-selection events bound to the body. + if ( event.cursor ) { + scope_Body.style.cursor = ''; + scope_Body.removeEventListener('selectstart', preventDefault); + } + + // Unbind the move and end events, which are added on 'start'. + scope_Listeners.forEach(function( c ) { + scope_DocumentElement.removeEventListener(c[0], c[1]); + }); + + // Remove dragging class. + removeClass(scope_Target, options.cssClasses.drag); + + setZindex(); + + data.handleNumbers.forEach(function(handleNumber){ + fireEvent('change', handleNumber); + fireEvent('set', handleNumber); + fireEvent('end', handleNumber); + }); + } + + // Bind move events on document. + function eventStart ( event, data ) { + + if ( data.handleNumbers.length === 1 ) { + + var handle = scope_Handles[data.handleNumbers[0]]; + + // Ignore 'disabled' handles + if ( handle.hasAttribute('disabled') ) { + return false; + } + + // Mark the handle as 'active' so it can be styled. + scope_ActiveHandle = handle.children[0]; + addClass(scope_ActiveHandle, options.cssClasses.active); + } + + // A drag should never propagate up to the 'tap' event. + event.stopPropagation(); + + // Attach the move and end events. + var moveEvent = attachEvent(actions.move, scope_DocumentElement, eventMove, { + startCalcPoint: event.calcPoint, + baseSize: baseSize(), + pageOffset: event.pageOffset, + handleNumbers: data.handleNumbers, + buttonsProperty: event.buttons, + locations: scope_Locations.slice() + }); + + var endEvent = attachEvent(actions.end, scope_DocumentElement, eventEnd, { + handleNumbers: data.handleNumbers + }); + + var outEvent = attachEvent("mouseout", scope_DocumentElement, documentLeave, { + handleNumbers: data.handleNumbers + }); + + scope_Listeners = moveEvent.concat(endEvent, outEvent); + + // Text selection isn't an issue on touch devices, + // so adding cursor styles can be skipped. + if ( event.cursor ) { + + // Prevent the 'I' cursor and extend the range-drag cursor. + scope_Body.style.cursor = getComputedStyle(event.target).cursor; + + // Mark the target with a dragging state. + if ( scope_Handles.length > 1 ) { + addClass(scope_Target, options.cssClasses.drag); + } + + // Prevent text selection when dragging the handles. + // In noUiSlider <= 9.2.0, this was handled by calling preventDefault on mouse/touch start/move, + // which is scroll blocking. The selectstart event is supported by FireFox starting from version 52, + // meaning the only holdout is iOS Safari. This doesn't matter: text selection isn't triggered there. + // The 'cursor' flag is false. + // See: http://caniuse.com/#search=selectstart + scope_Body.addEventListener('selectstart', preventDefault, false); + } + + data.handleNumbers.forEach(function(handleNumber){ + fireEvent('start', handleNumber); + }); + } + + // Move closest handle to tapped location. + function eventTap ( event ) { + + // The tap event shouldn't propagate up + event.stopPropagation(); + + var proposal = calcPointToPercentage(event.calcPoint); + var handleNumber = getClosestHandle(proposal); + + // Tackle the case that all handles are 'disabled'. + if ( handleNumber === false ) { + return false; + } + + // Flag the slider as it is now in a transitional state. + // Transition takes a configurable amount of ms (default 300). Re-enable the slider after that. + if ( !options.events.snap ) { + addClassFor(scope_Target, options.cssClasses.tap, options.animationDuration); + } + + setHandle(handleNumber, proposal, true, true); + + setZindex(); + + fireEvent('slide', handleNumber, true); + fireEvent('update', handleNumber, true); + fireEvent('change', handleNumber, true); + fireEvent('set', handleNumber, true); + + if ( options.events.snap ) { + eventStart(event, { handleNumbers: [handleNumber] }); + } + } + + // Fires a 'hover' event for a hovered mouse/pen position. + function eventHover ( event ) { + + var proposal = calcPointToPercentage(event.calcPoint); + + var to = scope_Spectrum.getStep(proposal); + var value = scope_Spectrum.fromStepping(to); + + Object.keys(scope_Events).forEach(function( targetEvent ) { + if ( 'hover' === targetEvent.split('.')[0] ) { + scope_Events[targetEvent].forEach(function( callback ) { + callback.call( scope_Self, value ); + }); + } + }); + } + + // Attach events to several slider parts. + function bindSliderEvents ( behaviour ) { + + // Attach the standard drag event to the handles. + if ( !behaviour.fixed ) { + + scope_Handles.forEach(function( handle, index ){ + + // These events are only bound to the visual handle + // element, not the 'real' origin element. + attachEvent ( actions.start, handle.children[0], eventStart, { + handleNumbers: [index] + }); + }); + } + + // Attach the tap event to the slider base. + if ( behaviour.tap ) { + attachEvent (actions.start, scope_Base, eventTap, {}); + } + + // Fire hover events + if ( behaviour.hover ) { + attachEvent (actions.move, scope_Base, eventHover, { hover: true }); + } + + // Make the range draggable. + if ( behaviour.drag ){ + + scope_Connects.forEach(function( connect, index ){ + + if ( connect === false || index === 0 || index === scope_Connects.length - 1 ) { + return; + } + + var handleBefore = scope_Handles[index - 1]; + var handleAfter = scope_Handles[index]; + var eventHolders = [connect]; + + addClass(connect, options.cssClasses.draggable); + + // When the range is fixed, the entire range can + // be dragged by the handles. The handle in the first + // origin will propagate the start event upward, + // but it needs to be bound manually on the other. + if ( behaviour.fixed ) { + eventHolders.push(handleBefore.children[0]); + eventHolders.push(handleAfter.children[0]); + } + + eventHolders.forEach(function( eventHolder ) { + attachEvent ( actions.start, eventHolder, eventStart, { + handles: [handleBefore, handleAfter], + handleNumbers: [index - 1, index] + }); + }); + }); + } + } + + + // Split out the handle positioning logic so the Move event can use it, too + function checkHandlePosition ( reference, handleNumber, to, lookBackward, lookForward, getValue ) { + + // For sliders with multiple handles, limit movement to the other handle. + // Apply the margin option by adding it to the handle positions. + if ( scope_Handles.length > 1 ) { + + if ( lookBackward && handleNumber > 0 ) { + to = Math.max(to, reference[handleNumber - 1] + options.margin); + } + + if ( lookForward && handleNumber < scope_Handles.length - 1 ) { + to = Math.min(to, reference[handleNumber + 1] - options.margin); + } + } + + // The limit option has the opposite effect, limiting handles to a + // maximum distance from another. Limit must be > 0, as otherwise + // handles would be unmoveable. + if ( scope_Handles.length > 1 && options.limit ) { + + if ( lookBackward && handleNumber > 0 ) { + to = Math.min(to, reference[handleNumber - 1] + options.limit); + } + + if ( lookForward && handleNumber < scope_Handles.length - 1 ) { + to = Math.max(to, reference[handleNumber + 1] - options.limit); + } + } + + // The padding option keeps the handles a certain distance from the + // edges of the slider. Padding must be > 0. + if ( options.padding ) { + + if ( handleNumber === 0 ) { + to = Math.max(to, options.padding); + } + + if ( handleNumber === scope_Handles.length - 1 ) { + to = Math.min(to, 100 - options.padding); + } + } + + to = scope_Spectrum.getStep(to); + + // Limit percentage to the 0 - 100 range + to = limit(to); + + // Return false if handle can't move + if ( to === reference[handleNumber] && !getValue ) { + return false; + } + + return to; + } + + function toPct ( pct ) { + return pct + '%'; + } + + // Updates scope_Locations and scope_Values, updates visual state + function updateHandlePosition ( handleNumber, to ) { + + // Update locations. + scope_Locations[handleNumber] = to; + + // Convert the value to the slider stepping/range. + scope_Values[handleNumber] = scope_Spectrum.fromStepping(to); + + // Called synchronously or on the next animationFrame + var stateUpdate = function() { + scope_Handles[handleNumber].style[options.style] = toPct(to); + updateConnect(handleNumber); + updateConnect(handleNumber + 1); + }; + + // Set the handle to the new position. + // Use requestAnimationFrame for efficient painting. + // No significant effect in Chrome, Edge sees dramatic performace improvements. + // Option to disable is useful for unit tests, and single-step debugging. + if ( window.requestAnimationFrame && options.useRequestAnimationFrame ) { + window.requestAnimationFrame(stateUpdate); + } else { + stateUpdate(); + } + } + + function setZindex ( ) { + + scope_HandleNumbers.forEach(function(handleNumber){ + // Handles before the slider middle are stacked later = higher, + // Handles after the middle later is lower + // [[7] [8] .......... | .......... [5] [4] + var dir = (scope_Locations[handleNumber] > 50 ? -1 : 1); + var zIndex = 3 + (scope_Handles.length + (dir * handleNumber)); + scope_Handles[handleNumber].childNodes[0].style.zIndex = zIndex; + }); + } + + // Test suggested values and apply margin, step. + function setHandle ( handleNumber, to, lookBackward, lookForward ) { + + to = checkHandlePosition(scope_Locations, handleNumber, to, lookBackward, lookForward, false); + + if ( to === false ) { + return false; + } + + updateHandlePosition(handleNumber, to); + + return true; + } + + // Updates style attribute for connect nodes + function updateConnect ( index ) { + + // Skip connects set to false + if ( !scope_Connects[index] ) { + return; + } + + var l = 0; + var h = 100; + + if ( index !== 0 ) { + l = scope_Locations[index - 1]; + } + + if ( index !== scope_Connects.length - 1 ) { + h = scope_Locations[index]; + } + + scope_Connects[index].style[options.style] = toPct(l); + scope_Connects[index].style[options.styleOposite] = toPct(100 - h); + } + + // ... + function setValue ( to, handleNumber ) { + + // Setting with null indicates an 'ignore'. + // Inputting 'false' is invalid. + if ( to === null || to === false ) { + return; + } + + // If a formatted number was passed, attemt to decode it. + if ( typeof to === 'number' ) { + to = String(to); + } + + to = options.format.from(to); + + // Request an update for all links if the value was invalid. + // Do so too if setting the handle fails. + if ( to !== false && !isNaN(to) ) { + setHandle(handleNumber, scope_Spectrum.toStepping(to), false, false); + } + } + + // Set the slider value. + function valueSet ( input, fireSetEvent ) { + + var values = asArray(input); + var isInit = scope_Locations[0] === undefined; + + // Event fires by default + fireSetEvent = (fireSetEvent === undefined ? true : !!fireSetEvent); + + values.forEach(setValue); + + // Animation is optional. + // Make sure the initial values were set before using animated placement. + if ( options.animate && !isInit ) { + addClassFor(scope_Target, options.cssClasses.tap, options.animationDuration); + } + + // Now that all base values are set, apply constraints + scope_HandleNumbers.forEach(function(handleNumber){ + setHandle(handleNumber, scope_Locations[handleNumber], true, false); + }); + + setZindex(); + + scope_HandleNumbers.forEach(function(handleNumber){ + + fireEvent('update', handleNumber); + + // Fire the event only for handles that received a new value, as per #579 + if ( values[handleNumber] !== null && fireSetEvent ) { + fireEvent('set', handleNumber); + } + }); + } + + // Reset slider to initial values + function valueReset ( fireSetEvent ) { + valueSet(options.start, fireSetEvent); + } + + // Get the slider value. + function valueGet ( ) { + + var values = scope_Values.map(options.format.to); + + // If only one handle is used, return a single value. + if ( values.length === 1 ){ + return values[0]; + } + + return values; + } + + // Removes classes from the root and empties it. + function destroy ( ) { + + for ( var key in options.cssClasses ) { + if ( !options.cssClasses.hasOwnProperty(key) ) { continue; } + removeClass(scope_Target, options.cssClasses[key]); + } + + while (scope_Target.firstChild) { + scope_Target.removeChild(scope_Target.firstChild); + } + + delete scope_Target.noUiSlider; + } + + // Get the current step size for the slider. + function getCurrentStep ( ) { + + // Check all locations, map them to their stepping point. + // Get the step point, then find it in the input list. + return scope_Locations.map(function( location, index ){ + + var nearbySteps = scope_Spectrum.getNearbySteps( location ); + var value = scope_Values[index]; + var increment = nearbySteps.thisStep.step; + var decrement = null; + + // If the next value in this step moves into the next step, + // the increment is the start of the next step - the current value + if ( increment !== false ) { + if ( value + increment > nearbySteps.stepAfter.startValue ) { + increment = nearbySteps.stepAfter.startValue - value; + } + } + + + // If the value is beyond the starting point + if ( value > nearbySteps.thisStep.startValue ) { + decrement = nearbySteps.thisStep.step; + } + + else if ( nearbySteps.stepBefore.step === false ) { + decrement = false; + } + + // If a handle is at the start of a step, it always steps back into the previous step first + else { + decrement = value - nearbySteps.stepBefore.highestStep; + } + + + // Now, if at the slider edges, there is not in/decrement + if ( location === 100 ) { + increment = null; + } + + else if ( location === 0 ) { + decrement = null; + } + + // As per #391, the comparison for the decrement step can have some rounding issues. + var stepDecimals = scope_Spectrum.countStepDecimals(); + + // Round per #391 + if ( increment !== null && increment !== false ) { + increment = Number(increment.toFixed(stepDecimals)); + } + + if ( decrement !== null && decrement !== false ) { + decrement = Number(decrement.toFixed(stepDecimals)); + } + + return [decrement, increment]; + }); + } + + // Attach an event to this slider, possibly including a namespace + function bindEvent ( namespacedEvent, callback ) { + scope_Events[namespacedEvent] = scope_Events[namespacedEvent] || []; + scope_Events[namespacedEvent].push(callback); + + // If the event bound is 'update,' fire it immediately for all handles. + if ( namespacedEvent.split('.')[0] === 'update' ) { + scope_Handles.forEach(function(a, index){ + fireEvent('update', index); + }); + } + } + + // Undo attachment of event + function removeEvent ( namespacedEvent ) { + + var event = namespacedEvent && namespacedEvent.split('.')[0]; + var namespace = event && namespacedEvent.substring(event.length); + + Object.keys(scope_Events).forEach(function( bind ){ + + var tEvent = bind.split('.')[0], + tNamespace = bind.substring(tEvent.length); + + if ( (!event || event === tEvent) && (!namespace || namespace === tNamespace) ) { + delete scope_Events[bind]; + } + }); + } + + // Updateable: margin, limit, padding, step, range, animate, snap + function updateOptions ( optionsToUpdate, fireSetEvent ) { + + // Spectrum is created using the range, snap, direction and step options. + // 'snap' and 'step' can be updated. + // If 'snap' and 'step' are not passed, they should remain unchanged. + var v = valueGet(); + + var updateAble = ['margin', 'limit', 'padding', 'range', 'animate', 'snap', 'step', 'format']; + + // Only change options that we're actually passed to update. + updateAble.forEach(function(name){ + if ( optionsToUpdate[name] !== undefined ) { + originalOptions[name] = optionsToUpdate[name]; + } + }); + + var newOptions = testOptions(originalOptions); + + // Load new options into the slider state + updateAble.forEach(function(name){ + if ( optionsToUpdate[name] !== undefined ) { + options[name] = newOptions[name]; + } + }); + + scope_Spectrum = newOptions.spectrum; + + // Limit, margin and padding depend on the spectrum but are stored outside of it. (#677) + options.margin = newOptions.margin; + options.limit = newOptions.limit; + options.padding = newOptions.padding; + + // Update pips, removes existing. + if ( options.pips ) { + pips(options.pips); + } + + // Invalidate the current positioning so valueSet forces an update. + scope_Locations = []; + valueSet(optionsToUpdate.start || v, fireSetEvent); + } + + // Throw an error if the slider was already initialized. + if ( scope_Target.noUiSlider ) { + throw new Error("noUiSlider (" + VERSION + "): Slider was already initialized."); + } + + // Create the base element, initialise HTML and set classes. + // Add handles and connect elements. + addSlider(scope_Target); + addElements(options.connect, scope_Base); + + scope_Self = { + destroy: destroy, + steps: getCurrentStep, + on: bindEvent, + off: removeEvent, + get: valueGet, + set: valueSet, + reset: valueReset, + // Exposed for unit testing, don't use this in your application. + __moveHandles: function(a, b, c) { moveHandles(a, b, scope_Locations, c); }, + options: originalOptions, // Issue #600, #678 + updateOptions: updateOptions, + target: scope_Target, // Issue #597 + removePips: removePips, + pips: pips // Issue #594 + }; + + // Attach user events. + bindSliderEvents(options.events); + + // Use the public value method to set the start values. + valueSet(options.start); + + if ( options.pips ) { + pips(options.pips); + } + + if ( options.tooltips ) { + tooltips(); + } + + aria(); + + return scope_Self; + +} + + + // Run the standard initializer + function initialize ( target, originalOptions ) { + + if ( !target || !target.nodeName ) { + throw new Error("noUiSlider (" + VERSION + "): create requires a single element, got: " + target); + } + + // Test the options and create the slider environment; + var options = testOptions( originalOptions, target ); + var api = closure( target, options, originalOptions ); + + target.noUiSlider = api; + + return api; + } + + // Use an object instead of a function for future expansibility; + return { + version: VERSION, + create: initialize + }; + +})); \ No newline at end of file diff --git a/js/nouislider.min.js b/js/nouislider.min.js new file mode 100644 index 000000000..b6f3032b5 --- /dev/null +++ b/js/nouislider.min.js @@ -0,0 +1,3 @@ +/*! nouislider - 10.0.0 - 2017-05-28 14:52:49 */ + +!function(a){"function"==typeof define&&define.amd?define([],a):"object"==typeof exports?module.exports=a():window.noUiSlider=a()}(function(){"use strict";function a(a){return"object"==typeof a&&"function"==typeof a.to&&"function"==typeof a.from}function b(a){a.parentElement.removeChild(a)}function c(a){a.preventDefault()}function d(a){return a.filter(function(a){return this[a]?!1:this[a]=!0},{})}function e(a,b){return Math.round(a/b)*b}function f(a,b){var c=a.getBoundingClientRect(),d=a.ownerDocument,e=d.documentElement,f=o(d);return/webkit.*Chrome.*Mobile/i.test(navigator.userAgent)&&(f.x=0),b?c.top+f.y-e.clientTop:c.left+f.x-e.clientLeft}function g(a){return"number"==typeof a&&!isNaN(a)&&isFinite(a)}function h(a,b,c){c>0&&(l(a,b),setTimeout(function(){m(a,b)},c))}function i(a){return Math.max(Math.min(a,100),0)}function j(a){return Array.isArray(a)?a:[a]}function k(a){a=String(a);var b=a.split(".");return b.length>1?b[1].length:0}function l(a,b){a.classList?a.classList.add(b):a.className+=" "+b}function m(a,b){a.classList?a.classList.remove(b):a.className=a.className.replace(new RegExp("(^|\\b)"+b.split(" ").join("|")+"(\\b|$)","gi")," ")}function n(a,b){return a.classList?a.classList.contains(b):new RegExp("\\b"+b+"\\b").test(a.className)}function o(a){var b=void 0!==window.pageXOffset,c="CSS1Compat"===(a.compatMode||""),d=b?window.pageXOffset:c?a.documentElement.scrollLeft:a.body.scrollLeft,e=b?window.pageYOffset:c?a.documentElement.scrollTop:a.body.scrollTop;return{x:d,y:e}}function p(){return window.navigator.pointerEnabled?{start:"pointerdown",move:"pointermove",end:"pointerup"}:window.navigator.msPointerEnabled?{start:"MSPointerDown",move:"MSPointerMove",end:"MSPointerUp"}:{start:"mousedown touchstart",move:"mousemove touchmove",end:"mouseup touchend"}}function q(){var a=!1;try{var b=Object.defineProperty({},"passive",{get:function(){a=!0}});window.addEventListener("test",null,b)}catch(c){}return a}function r(){return window.CSS&&CSS.supports&&CSS.supports("touch-action","none")}function s(a,b){return 100/(b-a)}function t(a,b){return 100*b/(a[1]-a[0])}function u(a,b){return t(a,a[0]<0?b+Math.abs(a[0]):b-a[0])}function v(a,b){return b*(a[1]-a[0])/100+a[0]}function w(a,b){for(var c=1;a>=b[c];)c+=1;return c}function x(a,b,c){if(c>=a.slice(-1)[0])return 100;var d,e,f,g,h=w(c,a);return d=a[h-1],e=a[h],f=b[h-1],g=b[h],f+u([d,e],c)/s(f,g)}function y(a,b,c){if(c>=100)return a.slice(-1)[0];var d,e,f,g,h=w(c,b);return d=a[h-1],e=a[h],f=b[h-1],g=b[h],v([d,e],(c-f)*s(f,g))}function z(a,b,c,d){if(100===d)return d;var f,g,h=w(d,a);return c?(f=a[h-1],g=a[h],d-f>(g-f)/2?g:f):b[h-1]?a[h-1]+e(d-a[h-1],b[h-1]):d}function A(a,b,c){var d;if("number"==typeof b&&(b=[b]),"[object Array]"!==Object.prototype.toString.call(b))throw new Error("noUiSlider ("+$+"): 'range' contains invalid value.");if(d="min"===a?0:"max"===a?100:parseFloat(a),!g(d)||!g(b[0]))throw new Error("noUiSlider ("+$+"): 'range' value isn't numeric.");c.xPct.push(d),c.xVal.push(b[0]),d?c.xSteps.push(isNaN(b[1])?!1:b[1]):isNaN(b[1])||(c.xSteps[0]=b[1]),c.xHighestCompleteStep.push(0)}function B(a,b,c){if(!b)return!0;c.xSteps[a]=t([c.xVal[a],c.xVal[a+1]],b)/s(c.xPct[a],c.xPct[a+1]);var d=(c.xVal[a+1]-c.xVal[a])/c.xNumSteps[a],e=Math.ceil(Number(d.toFixed(3))-1),f=c.xVal[a]+c.xNumSteps[a]*e;c.xHighestCompleteStep[a]=f}function C(a,b,c){this.xPct=[],this.xVal=[],this.xSteps=[c||!1],this.xNumSteps=[!1],this.xHighestCompleteStep=[],this.snap=b;var d,e=[];for(d in a)a.hasOwnProperty(d)&&e.push([a[d],d]);for(e.sort(e.length&&"object"==typeof e[0][0]?function(a,b){return a[0][0]-b[0][0]}:function(a,b){return a[0]-b[0]}),d=0;d=50)throw new Error("noUiSlider ("+$+"): 'padding' option must be less than half the range.")}}function P(a,b){switch(b){case"ltr":a.dir=0;break;case"rtl":a.dir=1;break;default:throw new Error("noUiSlider ("+$+"): 'direction' option was not recognized.")}}function Q(a,b){if("string"!=typeof b)throw new Error("noUiSlider ("+$+"): 'behaviour' must be a string containing options.");var c=b.indexOf("tap")>=0,d=b.indexOf("drag")>=0,e=b.indexOf("fixed")>=0,f=b.indexOf("snap")>=0,g=b.indexOf("hover")>=0;if(e){if(2!==a.handles)throw new Error("noUiSlider ("+$+"): 'fixed' behaviour must be used with 2 handles");M(a,a.start[1]-a.start[0])}a.events={tap:c||f,drag:d,fixed:e,snap:f,hover:g}}function R(a,b){if(b!==!1)if(b===!0){a.tooltips=[];for(var c=0;c=l;l=e(l,h)){for(n=ta.toStepping(l),o=n-k,r=o/a,s=Math.round(r),t=o/s,m=1;s>=m;m+=1)p=k+m*t,f[p.toFixed(5)]=["x",0];q=c.indexOf(l)>-1?1:"steps"===b?2:0,!g&&i&&(q=0),l===v&&j||(f[n.toFixed(5)]=[l,q]),k=n}}),f}function B(a,b,c){function d(a,b){var c=b===e.cssClasses.value,d=c?j:m,f=c?h:i;return b+" "+d[e.ort]+" "+f[a]}function f(a,f){f[1]=f[1]&&b?b(f[0],f[1]):f[1];var h=k(g,!1);h.className=d(f[1],e.cssClasses.marker),h.style[e.style]=a+"%",f[1]&&(h=k(g,!1),h.className=d(f[1],e.cssClasses.value),h.style[e.style]=a+"%",h.innerText=c.to(f[0]))}var g=xa.createElement("div"),h=[e.cssClasses.valueNormal,e.cssClasses.valueLarge,e.cssClasses.valueSub],i=[e.cssClasses.markerNormal,e.cssClasses.markerLarge,e.cssClasses.markerSub],j=[e.cssClasses.valueHorizontal,e.cssClasses.valueVertical],m=[e.cssClasses.markerHorizontal,e.cssClasses.markerVertical];return l(g,e.cssClasses.pips),l(g,0===e.ort?e.cssClasses.pipsHorizontal:e.cssClasses.pipsVertical),Object.keys(a).forEach(function(b){f(b,a[b])}),g}function C(){la&&(b(la),la=null)}function D(a){C();var b=a.mode,c=a.density||1,d=a.filter||!1,e=a.values||!1,f=a.stepped||!1,g=z(b,e,f),h=A(c,b,g),i=a.format||{to:Math.round};return la=pa.appendChild(B(h,d,i))}function E(){var a=ha.getBoundingClientRect(),b="offset"+["Width","Height"][e.ort];return 0===e.ort?a.width||ha[b]:a.height||ha[b]}function F(a,b,c,d){var f=function(b){return pa.hasAttribute("disabled")?!1:n(pa,e.cssClasses.tap)?!1:(b=G(b,d.pageOffset))?a===ma.start&&void 0!==b.buttons&&b.buttons>1?!1:d.hover&&b.buttons?!1:(oa||b.preventDefault(),b.calcPoint=b.points[e.ort],void c(b,d)):!1},g=[];return a.split(" ").forEach(function(a){b.addEventListener(a,f,oa?{passive:!0}:!1),g.push([a,f])}),g}function G(a,b){var c,d,e=0===a.type.indexOf("touch"),f=0===a.type.indexOf("mouse"),g=0===a.type.indexOf("pointer");if(0===a.type.indexOf("MSPointer")&&(g=!0),e){if(a.touches.length>1)return!1;c=a.changedTouches[0].pageX,d=a.changedTouches[0].pageY}return b=b||o(xa),(f||g)&&(c=a.clientX+b.x,d=a.clientY+b.y),a.pageOffset=b,a.points=[c,d],a.cursor=f||g,a}function H(a){var b=a-f(ha,e.ort),c=100*b/E();return e.dir?100-c:c}function I(a){var b=100,c=!1;return ia.forEach(function(d,e){if(!d.hasAttribute("disabled")){var f=Math.abs(qa[e]-a);b>f&&(c=e,b=f)}}),c}function J(a,b,c,d){var e=c.slice(),f=[!a,a],g=[a,!a];d=d.slice(),a&&d.reverse(),d.length>1?d.forEach(function(a,c){var d=S(e,a,e[a]+b,f[c],g[c],!1);d===!1?b=0:(b=d-e[a],e[a]=d)}):f=g=[!0];var h=!1;d.forEach(function(a,d){h=W(a,c[a]+b,f[d],g[d])||h}),h&&d.forEach(function(a){K("update",a),K("slide",a)})}function K(a,b,c){Object.keys(va).forEach(function(d){var f=d.split(".")[0];a===f&&va[d].forEach(function(a){a.call(ka,ua.map(e.format.to),b,ua.slice(),c||!1,qa.slice())})})}function L(a,b){"mouseout"===a.type&&"HTML"===a.target.nodeName&&null===a.relatedTarget&&N(a,b)}function M(a,b){if(-1===navigator.appVersion.indexOf("MSIE 9")&&0===a.buttons&&0!==b.buttonsProperty)return N(a,b);var c=(e.dir?-1:1)*(a.calcPoint-b.startCalcPoint),d=100*c/b.baseSize;J(c>0,d,b.locations,b.handleNumbers)}function N(a,b){sa&&(m(sa,e.cssClasses.active),sa=!1),a.cursor&&(za.style.cursor="",za.removeEventListener("selectstart",c)),wa.forEach(function(a){ya.removeEventListener(a[0],a[1])}),m(pa,e.cssClasses.drag),V(),b.handleNumbers.forEach(function(a){K("change",a),K("set",a),K("end",a)})}function O(a,b){if(1===b.handleNumbers.length){var d=ia[b.handleNumbers[0]];if(d.hasAttribute("disabled"))return!1;sa=d.children[0],l(sa,e.cssClasses.active)}a.stopPropagation();var f=F(ma.move,ya,M,{startCalcPoint:a.calcPoint,baseSize:E(),pageOffset:a.pageOffset,handleNumbers:b.handleNumbers,buttonsProperty:a.buttons,locations:qa.slice()}),g=F(ma.end,ya,N,{handleNumbers:b.handleNumbers}),h=F("mouseout",ya,L,{handleNumbers:b.handleNumbers});wa=f.concat(g,h),a.cursor&&(za.style.cursor=getComputedStyle(a.target).cursor,ia.length>1&&l(pa,e.cssClasses.drag),za.addEventListener("selectstart",c,!1)),b.handleNumbers.forEach(function(a){K("start",a)})}function P(a){a.stopPropagation();var b=H(a.calcPoint),c=I(b);return c===!1?!1:(e.events.snap||h(pa,e.cssClasses.tap,e.animationDuration),W(c,b,!0,!0),V(),K("slide",c,!0),K("update",c,!0),K("change",c,!0),K("set",c,!0),void(e.events.snap&&O(a,{handleNumbers:[c]})))}function Q(a){var b=H(a.calcPoint),c=ta.getStep(b),d=ta.fromStepping(c);Object.keys(va).forEach(function(a){"hover"===a.split(".")[0]&&va[a].forEach(function(a){a.call(ka,d)})})}function R(a){a.fixed||ia.forEach(function(a,b){F(ma.start,a.children[0],O,{handleNumbers:[b]})}),a.tap&&F(ma.start,ha,P,{}),a.hover&&F(ma.move,ha,Q,{hover:!0}),a.drag&&ja.forEach(function(b,c){if(b!==!1&&0!==c&&c!==ja.length-1){var d=ia[c-1],f=ia[c],g=[b];l(b,e.cssClasses.draggable),a.fixed&&(g.push(d.children[0]),g.push(f.children[0])),g.forEach(function(a){F(ma.start,a,O,{handles:[d,f],handleNumbers:[c-1,c]})})}})}function S(a,b,c,d,f,g){return ia.length>1&&(d&&b>0&&(c=Math.max(c,a[b-1]+e.margin)),f&&b1&&e.limit&&(d&&b>0&&(c=Math.min(c,a[b-1]+e.limit)),f&&b50?-1:1,c=3+(ia.length+b*a);ia[a].childNodes[0].style.zIndex=c})}function W(a,b,c,d){return b=S(qa,a,b,c,d,!1),b===!1?!1:(U(a,b),!0)}function Y(a){if(ja[a]){var b=0,c=100;0!==a&&(b=qa[a-1]),a!==ja.length-1&&(c=qa[a]),ja[a].style[e.style]=T(b),ja[a].style[e.styleOposite]=T(100-c)}}function Z(a,b){null!==a&&a!==!1&&("number"==typeof a&&(a=String(a)),a=e.format.from(a),a===!1||isNaN(a)||W(b,ta.toStepping(a),!1,!1))}function _(a,b){var c=j(a),d=void 0===qa[0];b=void 0===b?!0:!!b,c.forEach(Z),e.animate&&!d&&h(pa,e.cssClasses.tap,e.animationDuration),ra.forEach(function(a){W(a,qa[a],!0,!1)}),V(),ra.forEach(function(a){K("update",a),null!==c[a]&&b&&K("set",a)})}function aa(a){_(e.start,a)}function ba(){var a=ua.map(e.format.to);return 1===a.length?a[0]:a}function ca(){for(var a in e.cssClasses)e.cssClasses.hasOwnProperty(a)&&m(pa,e.cssClasses[a]);for(;pa.firstChild;)pa.removeChild(pa.firstChild);delete pa.noUiSlider}function da(){return qa.map(function(a,b){var c=ta.getNearbySteps(a),d=ua[b],e=c.thisStep.step,f=null;e!==!1&&d+e>c.stepAfter.startValue&&(e=c.stepAfter.startValue-d),f=d>c.thisStep.startValue?c.thisStep.step:c.stepBefore.step===!1?!1:d-c.stepBefore.highestStep,100===a?e=null:0===a&&(f=null);var g=ta.countStepDecimals();return null!==e&&e!==!1&&(e=Number(e.toFixed(g))),null!==f&&f!==!1&&(f=Number(f.toFixed(g))),[f,e]})}function ea(a,b){va[a]=va[a]||[],va[a].push(b),"update"===a.split(".")[0]&&ia.forEach(function(a,b){K("update",b)})}function fa(a){var b=a&&a.split(".")[0],c=b&&a.substring(b.length);Object.keys(va).forEach(function(a){var d=a.split(".")[0],e=a.substring(d.length);b&&b!==d||c&&c!==e||delete va[a]})}function ga(a,b){var c=ba(),d=["margin","limit","padding","range","animate","snap","step","format"];d.forEach(function(b){void 0!==a[b]&&(g[b]=a[b])});var f=X(g);d.forEach(function(b){void 0!==a[b]&&(e[b]=f[b])}),ta=f.spectrum,e.margin=f.margin,e.limit=f.limit,e.padding=f.padding,e.pips&&D(e.pips),qa=[],_(a.start||c,b)}var ha,ia,ja,ka,la,ma=p(),na=r(),oa=na&&q(),pa=a,qa=[],ra=[],sa=!1,ta=e.spectrum,ua=[],va={},wa=null,xa=a.ownerDocument,ya=xa.documentElement,za=xa.body;if(pa.noUiSlider)throw new Error("noUiSlider ("+$+"): Slider was already initialized.");return v(pa),u(e.connect,ha),ka={destroy:ca,steps:da,on:ea,off:fa,get:ba,set:_,reset:aa,__moveHandles:function(a,b,c){J(a,b,qa,c)},options:g,updateOptions:ga,target:pa,removePips:C,pips:D},R(e.events),_(e.start),e.pips&&D(e.pips),e.tooltips&&x(),y(),ka}function Z(a,b){if(!a||!a.nodeName)throw new Error("noUiSlider ("+$+"): create requires a single element, got: "+a);var c=X(b,a),d=Y(a,c,b);return a.noUiSlider=d,d}var $="10.0.0";C.prototype.getMargin=function(a){var b=this.xNumSteps[0];if(b&&a/b%1!==0)throw new Error("noUiSlider ("+$+"): 'limit', 'margin' and 'padding' must be divisible by step.");return 2===this.xPct.length?t(this.xVal,a):!1},C.prototype.toStepping=function(a){return a=x(this.xVal,this.xPct,a)},C.prototype.fromStepping=function(a){return y(this.xVal,this.xPct,a)},C.prototype.getStep=function(a){return a=z(this.xPct,this.xSteps,this.snap,a)},C.prototype.getNearbySteps=function(a){var b=w(a,this.xPct);return{stepBefore:{startValue:this.xVal[b-2],step:this.xNumSteps[b-2],highestStep:this.xHighestCompleteStep[b-2]},thisStep:{startValue:this.xVal[b-1],step:this.xNumSteps[b-1],highestStep:this.xHighestCompleteStep[b-1]},stepAfter:{startValue:this.xVal[b-0],step:this.xNumSteps[b-0],highestStep:this.xHighestCompleteStep[b-0]}}},C.prototype.countStepDecimals=function(){var a=this.xNumSteps.map(k);return Math.max.apply(null,a)},C.prototype.convert=function(a){return this.getStep(this.toStepping(a))};var _={to:function(a){return void 0!==a&&a.toFixed(2)},from:Number};return{version:$,create:Z}}); \ No newline at end of file diff --git a/js/openseadragon/openseadragon-2.3.1.js b/js/openseadragon/openseadragon-2.3.1.js new file mode 100644 index 000000000..c5303262d --- /dev/null +++ b/js/openseadragon/openseadragon-2.3.1.js @@ -0,0 +1,22092 @@ +//! openseadragon 2.3.1 +//! Built on 2017-09-19 +//! Git commit: v2.3.1-0-08414cd +//! http://openseadragon.github.io +//! License: http://openseadragon.github.io/license/ + +/* + * OpenSeadragon + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Portions of this source file taken from jQuery: + * + * Copyright 2011 John Resig + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Portions of this source file taken from mattsnider.com: + * + * Copyright (c) 2006-2013 Matt Snider + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * @namespace OpenSeadragon + * @version openseadragon 2.3.1 + * @classdesc The root namespace for OpenSeadragon. All utility methods + * and classes are defined on or below this namespace. + * + */ + + +// Typedefs + + /** + * All required and optional settings for instantiating a new instance of an OpenSeadragon image viewer. + * + * @typedef {Object} Options + * @memberof OpenSeadragon + * + * @property {String} id + * Id of the element to append the viewer's container element to. If not provided, the 'element' property must be provided. + * If both the element and id properties are specified, the viewer is appended to the element provided in the element property. + * + * @property {Element} element + * The element to append the viewer's container element to. If not provided, the 'id' property must be provided. + * If both the element and id properties are specified, the viewer is appended to the element provided in the element property. + * + * @property {Array|String|Function|Object} [tileSources=null] + * Tile source(s) to open initially. This is a complex parameter; see + * {@link OpenSeadragon.Viewer#open} for details. + * + * @property {Number} [tabIndex=0] + * Tabbing order index to assign to the viewer element. Positive values are selected in increasing order. When tabIndex is 0 + * source order is used. A negative value omits the viewer from the tabbing order. + * + * @property {Array} overlays Array of objects defining permanent overlays of + * the viewer. The overlays added via this option and later removed with + * {@link OpenSeadragon.Viewer#removeOverlay} will be added back when a new + * image is opened. + * To add overlays which can be definitively removed, one must use + * {@link OpenSeadragon.Viewer#addOverlay} + * If displaying a sequence of images, the overlays can be associated + * with a specific page by passing the overlays array to the page's + * tile source configuration. + * Expected properties: + * * x, y, (or px, py for pixel coordinates) to define the location. + * * width, height in point if using x,y or in pixels if using px,py. If width + * and height are specified, the overlay size is adjusted when zooming, + * otherwise the size stays the size of the content (or the size defined by CSS). + * * className to associate a class to the overlay + * * id to set the overlay element. If an element with this id already exists, + * it is reused, otherwise it is created. If not specified, a new element is + * created. + * * placement a string to define the relative position to the viewport. + * Only used if no width and height are specified. Default: 'TOP_LEFT'. + * See {@link OpenSeadragon.Placement} for possible values. + * + * @property {String} [xmlPath=null] + * DEPRECATED. A relative path to load a DZI file from the server. + * Prefer the newer Options.tileSources. + * + * @property {String} [prefixUrl='/images/'] + * Prepends the prefixUrl to navImages paths, which is very useful + * since the default paths are rarely useful for production + * environments. + * + * @property {OpenSeadragon.NavImages} [navImages] + * An object with a property for each button or other built-in navigation + * control, eg the current 'zoomIn', 'zoomOut', 'home', and 'fullpage'. + * Each of those in turn provides an image path for each state of the button + * or navigation control, eg 'REST', 'GROUP', 'HOVER', 'PRESS'. Finally the + * image paths, by default assume there is a folder on the servers root path + * called '/images', eg '/images/zoomin_rest.png'. If you need to adjust + * these paths, prefer setting the option.prefixUrl rather than overriding + * every image path directly through this setting. + * + * @property {Boolean} [debugMode=false] + * TODO: provide an in-screen panel providing event detail feedback. + * + * @property {String} [debugGridColor=['#437AB2', '#1B9E77', '#D95F02', '#7570B3', '#E7298A', '#66A61E', '#E6AB02', '#A6761D', '#666666']] + * The colors of grids in debug mode. Each tiled image's grid uses a consecutive color. + * If there are more tiled images than provided colors, the color vector is recycled. + * + * @property {Number} [blendTime=0] + * Specifies the duration of animation as higher or lower level tiles are + * replacing the existing tile. + * + * @property {Boolean} [alwaysBlend=false] + * Forces the tile to always blend. By default the tiles skip blending + * when the blendTime is surpassed and the current animation frame would + * not complete the blend. + * + * @property {Boolean} [autoHideControls=true] + * If the user stops interacting with the viewport, fade the navigation + * controls. Useful for presentation since the controls are by default + * floated on top of the image the user is viewing. + * + * @property {Boolean} [immediateRender=false] + * Render the best closest level first, ignoring the lowering levels which + * provide the effect of very blurry to sharp. It is recommended to change + * setting to true for mobile devices. + * + * @property {Number} [defaultZoomLevel=0] + * Zoom level to use when image is first opened or the home button is clicked. + * If 0, adjusts to fit viewer. + * + * @property {Number} [opacity=1] + * Default proportional opacity of the tiled images (1=opaque, 0=hidden) + * Hidden images do not draw and only load when preloading is allowed. + * + * @property {Boolean} [preload=false] + * Default switch for loading hidden images (true loads, false blocks) + * + * @property {String} [compositeOperation=null] + * Valid values are 'source-over', 'source-atop', 'source-in', 'source-out', + * 'destination-over', 'destination-atop', 'destination-in', + * 'destination-out', 'lighter', 'copy' or 'xor' + * + * @property {String|CanvasGradient|CanvasPattern|Function} [placeholderFillStyle=null] + * Draws a colored rectangle behind the tile if it is not loaded yet. + * You can pass a CSS color value like "#FF8800". + * When passing a function the tiledImage and canvas context are available as argument which is useful when you draw a gradient or pattern. + * + * @property {Number} [degrees=0] + * Initial rotation. + * + * @property {Number} [minZoomLevel=null] + * + * @property {Number} [maxZoomLevel=null] + * + * @property {Boolean} [homeFillsViewer=false] + * Make the 'home' button fill the viewer and clip the image, instead + * of fitting the image to the viewer and letterboxing. + * + * @property {Boolean} [panHorizontal=true] + * Allow horizontal pan. + * + * @property {Boolean} [panVertical=true] + * Allow vertical pan. + * + * @property {Boolean} [constrainDuringPan=false] + * + * @property {Boolean} [wrapHorizontal=false] + * Set to true to force the image to wrap horizontally within the viewport. + * Useful for maps or images representing the surface of a sphere or cylinder. + * + * @property {Boolean} [wrapVertical=false] + * Set to true to force the image to wrap vertically within the viewport. + * Useful for maps or images representing the surface of a sphere or cylinder. + * + * @property {Number} [minZoomImageRatio=0.9] + * The minimum percentage ( expressed as a number between 0 and 1 ) of + * the viewport height or width at which the zoom out will be constrained. + * Setting it to 0, for example will allow you to zoom out infinity. + * + * @property {Number} [maxZoomPixelRatio=1.1] + * The maximum ratio to allow a zoom-in to affect the highest level pixel + * ratio. This can be set to Infinity to allow 'infinite' zooming into the + * image though it is less effective visually if the HTML5 Canvas is not + * availble on the viewing device. + * + * @property {Number} [smoothTileEdgesMinZoom=1.1] + * A zoom percentage ( where 1 is 100% ) of the highest resolution level. + * When zoomed in beyond this value alternative compositing will be used to + * smooth out the edges between tiles. This will have a performance impact. + * Can be set to Infinity to turn it off. + * Note: This setting is ignored on iOS devices due to a known bug (See {@link https://github.com/openseadragon/openseadragon/issues/952}) + * + * @property {Boolean} [iOSDevice=?] + * True if running on an iOS device, false otherwise. + * Used to disable certain features that behave differently on iOS devices. + * + * @property {Boolean} [autoResize=true] + * Set to false to prevent polling for viewer size changes. Useful for providing custom resize behavior. + * + * @property {Boolean} [preserveImageSizeOnResize=false] + * Set to true to have the image size preserved when the viewer is resized. This requires autoResize=true (default). + * + * @property {Number} [minScrollDeltaTime=50] + * Number of milliseconds between canvas-scroll events. This value helps normalize the rate of canvas-scroll + * events between different devices, causing the faster devices to slow down enough to make the zoom control + * more manageable. + * + * @property {Number} [pixelsPerWheelLine=40] + * For pixel-resolution scrolling devices, the number of pixels equal to one scroll line. + * + * @property {Number} [visibilityRatio=0.5] + * The percentage ( as a number from 0 to 1 ) of the source image which + * must be kept within the viewport. If the image is dragged beyond that + * limit, it will 'bounce' back until the minimum visibility ratio is + * achieved. Setting this to 0 and wrapHorizontal ( or wrapVertical ) to + * true will provide the effect of an infinitely scrolling viewport. + * + * @property {Object} [viewportMargins={}] + * Pushes the "home" region in from the sides by the specified amounts. + * Possible subproperties (Numbers, in screen coordinates): left, top, right, bottom. + * + * @property {Number} [imageLoaderLimit=0] + * The maximum number of image requests to make concurrently. By default + * it is set to 0 allowing the browser to make the maximum number of + * image requests in parallel as allowed by the browsers policy. + * + * @property {Number} [clickTimeThreshold=300] + * The number of milliseconds within which a pointer down-up event combination + * will be treated as a click gesture. + * + * @property {Number} [clickDistThreshold=5] + * The maximum distance allowed between a pointer down event and a pointer up event + * to be treated as a click gesture. + * + * @property {Number} [dblClickTimeThreshold=300] + * The number of milliseconds within which two pointer down-up event combinations + * will be treated as a double-click gesture. + * + * @property {Number} [dblClickDistThreshold=20] + * The maximum distance allowed between two pointer click events + * to be treated as a double-click gesture. + * + * @property {Number} [springStiffness=6.5] + * + * @property {Number} [animationTime=1.2] + * Specifies the animation duration per each {@link OpenSeadragon.Spring} + * which occur when the image is dragged or zoomed. + * + * @property {OpenSeadragon.GestureSettings} [gestureSettingsMouse] + * Settings for gestures generated by a mouse pointer device. (See {@link OpenSeadragon.GestureSettings}) + * @property {Boolean} [gestureSettingsMouse.scrollToZoom=true] - Zoom on scroll gesture + * @property {Boolean} [gestureSettingsMouse.clickToZoom=true] - Zoom on click gesture + * @property {Boolean} [gestureSettingsMouse.dblClickToZoom=false] - Zoom on double-click gesture. Note: If set to true + * then clickToZoom should be set to false to prevent multiple zooms. + * @property {Boolean} [gestureSettingsMouse.pinchToZoom=false] - Zoom on pinch gesture + * @property {Boolean} [gestureSettingsMouse.flickEnabled=false] - Enable flick gesture + * @property {Number} [gestureSettingsMouse.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second) + * @property {Number} [gestureSettingsMouse.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture + * @property {Boolean} [gestureSettingsMouse.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers. + * + * @property {OpenSeadragon.GestureSettings} [gestureSettingsTouch] + * Settings for gestures generated by a touch pointer device. (See {@link OpenSeadragon.GestureSettings}) + * @property {Boolean} [gestureSettingsTouch.scrollToZoom=false] - Zoom on scroll gesture + * @property {Boolean} [gestureSettingsTouch.clickToZoom=false] - Zoom on click gesture + * @property {Boolean} [gestureSettingsTouch.dblClickToZoom=true] - Zoom on double-click gesture. Note: If set to true + * then clickToZoom should be set to false to prevent multiple zooms. + * @property {Boolean} [gestureSettingsTouch.pinchToZoom=true] - Zoom on pinch gesture + * @property {Boolean} [gestureSettingsTouch.flickEnabled=true] - Enable flick gesture + * @property {Number} [gestureSettingsTouch.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second) + * @property {Number} [gestureSettingsTouch.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture + * @property {Boolean} [gestureSettingsTouch.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers. + * + * @property {OpenSeadragon.GestureSettings} [gestureSettingsPen] + * Settings for gestures generated by a pen pointer device. (See {@link OpenSeadragon.GestureSettings}) + * @property {Boolean} [gestureSettingsPen.scrollToZoom=false] - Zoom on scroll gesture + * @property {Boolean} [gestureSettingsPen.clickToZoom=true] - Zoom on click gesture + * @property {Boolean} [gestureSettingsPen.dblClickToZoom=false] - Zoom on double-click gesture. Note: If set to true + * then clickToZoom should be set to false to prevent multiple zooms. + * @property {Boolean} [gestureSettingsPen.pinchToZoom=false] - Zoom on pinch gesture + * @property {Boolean} [gestureSettingsPen.flickEnabled=false] - Enable flick gesture + * @property {Number} [gestureSettingsPen.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second) + * @property {Number} [gestureSettingsPen.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture + * @property {Boolean} [gestureSettingsPen.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers. + * + * @property {OpenSeadragon.GestureSettings} [gestureSettingsUnknown] + * Settings for gestures generated by unknown pointer devices. (See {@link OpenSeadragon.GestureSettings}) + * @property {Boolean} [gestureSettingsUnknown.scrollToZoom=true] - Zoom on scroll gesture + * @property {Boolean} [gestureSettingsUnknown.clickToZoom=false] - Zoom on click gesture + * @property {Boolean} [gestureSettingsUnknown.dblClickToZoom=true] - Zoom on double-click gesture. Note: If set to true + * then clickToZoom should be set to false to prevent multiple zooms. + * @property {Boolean} [gestureSettingsUnknown.pinchToZoom=true] - Zoom on pinch gesture + * @property {Boolean} [gestureSettingsUnknown.flickEnabled=true] - Enable flick gesture + * @property {Number} [gestureSettingsUnknown.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second) + * @property {Number} [gestureSettingsUnknown.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture + * @property {Boolean} [gestureSettingsUnknown.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers. + * + * @property {Number} [zoomPerClick=2.0] + * The "zoom distance" per mouse click or touch tap. Note: Setting this to 1.0 effectively disables the click-to-zoom feature (also see gestureSettings[Mouse|Touch|Pen].clickToZoom/dblClickToZoom). + * + * @property {Number} [zoomPerScroll=1.2] + * The "zoom distance" per mouse scroll or touch pinch. Note: Setting this to 1.0 effectively disables the mouse-wheel zoom feature (also see gestureSettings[Mouse|Touch|Pen].scrollToZoom}). + * + * @property {Number} [zoomPerSecond=1.0] + * The number of seconds to animate a single zoom event over. + * + * @property {Boolean} [showNavigator=false] + * Set to true to make the navigator minimap appear. + * + * @property {String} [navigatorId=navigator-GENERATED DATE] + * The ID of a div to hold the navigator minimap. + * If an ID is specified, the navigatorPosition, navigatorSizeRatio, navigatorMaintainSizeRatio, navigator[Top|Left|Height|Width] and navigatorAutoFade options will be ignored. + * If an ID is not specified, a div element will be generated and placed on top of the main image. + * + * @property {String} [navigatorPosition='TOP_RIGHT'] + * Valid values are 'TOP_LEFT', 'TOP_RIGHT', 'BOTTOM_LEFT', 'BOTTOM_RIGHT', or 'ABSOLUTE'.
      + * If 'ABSOLUTE' is specified, then navigator[Top|Left|Height|Width] determines the size and position of the navigator minimap in the viewer, and navigatorSizeRatio and navigatorMaintainSizeRatio are ignored.
      + * For 'TOP_LEFT', 'TOP_RIGHT', 'BOTTOM_LEFT', and 'BOTTOM_RIGHT', the navigatorSizeRatio or navigator[Height|Width] values determine the size of the navigator minimap. + * + * @property {Number} [navigatorSizeRatio=0.2] + * Ratio of navigator size to viewer size. Ignored if navigator[Height|Width] are specified. + * + * @property {Boolean} [navigatorMaintainSizeRatio=false] + * If true, the navigator minimap is resized (using navigatorSizeRatio) when the viewer size changes. + * + * @property {Number|String} [navigatorTop=null] + * Specifies the location of the navigator minimap (see navigatorPosition). + * + * @property {Number|String} [navigatorLeft=null] + * Specifies the location of the navigator minimap (see navigatorPosition). + * + * @property {Number|String} [navigatorHeight=null] + * Specifies the size of the navigator minimap (see navigatorPosition). + * If specified, navigatorSizeRatio and navigatorMaintainSizeRatio are ignored. + * + * @property {Number|String} [navigatorWidth=null] + * Specifies the size of the navigator minimap (see navigatorPosition). + * If specified, navigatorSizeRatio and navigatorMaintainSizeRatio are ignored. + * + * @property {Boolean} [navigatorAutoResize=true] + * Set to false to prevent polling for navigator size changes. Useful for providing custom resize behavior. + * Setting to false can also improve performance when the navigator is configured to a fixed size. + * + * @property {Boolean} [navigatorAutoFade=true] + * If the user stops interacting with the viewport, fade the navigator minimap. + * Setting to false will make the navigator minimap always visible. + * + * @property {Boolean} [navigatorRotate=true] + * If true, the navigator will be rotated together with the viewer. + * + * @property {Number} [controlsFadeDelay=2000] + * The number of milliseconds to wait once the user has stopped interacting + * with the interface before begining to fade the controls. Assumes + * showNavigationControl and autoHideControls are both true. + * + * @property {Number} [controlsFadeLength=1500] + * The number of milliseconds to animate the controls fading out. + * + * @property {Number} [maxImageCacheCount=200] + * The max number of images we should keep in memory (per drawer). + * + * @property {Number} [timeout=30000] + * The max number of milliseconds that an image job may take to complete. + * + * @property {Boolean} [useCanvas=true] + * Set to false to not use an HTML canvas element for image rendering even if canvas is supported. + * + * @property {Number} [minPixelRatio=0.5] + * The higher the minPixelRatio, the lower the quality of the image that + * is considered sufficient to stop rendering a given zoom level. For + * example, if you are targeting mobile devices with less bandwith you may + * try setting this to 1.5 or higher. + * + * @property {Boolean} [mouseNavEnabled=true] + * Is the user able to interact with the image via mouse or touch. Default + * interactions include draging the image in a plane, and zooming in toward + * and away from the image. + * + * @property {Boolean} [showNavigationControl=true] + * Set to false to prevent the appearance of the default navigation controls.
      + * Note that if set to false, the customs buttons set by the options + * zoomInButton, zoomOutButton etc, are rendered inactive. + * + * @property {OpenSeadragon.ControlAnchor} [navigationControlAnchor=TOP_LEFT] + * Placement of the default navigation controls. + * To set the placement of the sequence controls, see the + * sequenceControlAnchor option. + * + * @property {Boolean} [showZoomControl=true] + * If true then + and - buttons to zoom in and out are displayed.
      + * Note: {@link OpenSeadragon.Options.showNavigationControl} is overriding + * this setting when set to false. + * + * @property {Boolean} [showHomeControl=true] + * If true then the 'Go home' button is displayed to go back to the original + * zoom and pan.
      + * Note: {@link OpenSeadragon.Options.showNavigationControl} is overriding + * this setting when set to false. + * + * @property {Boolean} [showFullPageControl=true] + * If true then the 'Toggle full page' button is displayed to switch + * between full page and normal mode.
      + * Note: {@link OpenSeadragon.Options.showNavigationControl} is overriding + * this setting when set to false. + * + * @property {Boolean} [showRotationControl=false] + * If true then the rotate left/right controls will be displayed as part of the + * standard controls. This is also subject to the browser support for rotate + * (e.g. viewer.drawer.canRotate()).
      + * Note: {@link OpenSeadragon.Options.showNavigationControl} is overriding + * this setting when set to false. + * + * @property {Boolean} [showSequenceControl=true] + * If sequenceMode is true, then provide buttons for navigating forward and + * backward through the images. + * + * @property {OpenSeadragon.ControlAnchor} [sequenceControlAnchor=TOP_LEFT] + * Placement of the default sequence controls. + * + * @property {Boolean} [navPrevNextWrap=false] + * If true then the 'previous' button will wrap to the last image when + * viewing the first image and the 'next' button will wrap to the first + * image when viewing the last image. + * + * @property {String} zoomInButton + * Set the id of the custom 'Zoom in' button to use. + * This is useful to have a custom button anywhere in the web page.
      + * To only change the button images, consider using + * {@link OpenSeadragon.Options.navImages} + * + * @property {String} zoomOutButton + * Set the id of the custom 'Zoom out' button to use. + * This is useful to have a custom button anywhere in the web page.
      + * To only change the button images, consider using + * {@link OpenSeadragon.Options.navImages} + * + * @property {String} homeButton + * Set the id of the custom 'Go home' button to use. + * This is useful to have a custom button anywhere in the web page.
      + * To only change the button images, consider using + * {@link OpenSeadragon.Options.navImages} + * + * @property {String} fullPageButton + * Set the id of the custom 'Toggle full page' button to use. + * This is useful to have a custom button anywhere in the web page.
      + * To only change the button images, consider using + * {@link OpenSeadragon.Options.navImages} + * + * @property {String} rotateLeftButton + * Set the id of the custom 'Rotate left' button to use. + * This is useful to have a custom button anywhere in the web page.
      + * To only change the button images, consider using + * {@link OpenSeadragon.Options.navImages} + * + * @property {String} rotateRightButton + * Set the id of the custom 'Rotate right' button to use. + * This is useful to have a custom button anywhere in the web page.
      + * To only change the button images, consider using + * {@link OpenSeadragon.Options.navImages} + * + * @property {String} previousButton + * Set the id of the custom 'Previous page' button to use. + * This is useful to have a custom button anywhere in the web page.
      + * To only change the button images, consider using + * {@link OpenSeadragon.Options.navImages} + * + * @property {String} nextButton + * Set the id of the custom 'Next page' button to use. + * This is useful to have a custom button anywhere in the web page.
      + * To only change the button images, consider using + * {@link OpenSeadragon.Options.navImages} + * + * @property {Boolean} [sequenceMode=false] + * Set to true to have the viewer treat your tilesources as a sequence of images to + * be opened one at a time rather than all at once. + * + * @property {Number} [initialPage=0] + * If sequenceMode is true, display this page initially. + * + * @property {Boolean} [preserveViewport=false] + * If sequenceMode is true, then normally navigating through each image resets the + * viewport to 'home' position. If preserveViewport is set to true, then the viewport + * position is preserved when navigating between images in the sequence. + * + * @property {Boolean} [preserveOverlays=false] + * If sequenceMode is true, then normally navigating through each image + * resets the overlays. + * If preserveOverlays is set to true, then the overlays added with {@link OpenSeadragon.Viewer#addOverlay} + * are preserved when navigating between images in the sequence. + * Note: setting preserveOverlays overrides any overlays specified in the global + * "overlays" option for the Viewer. It's also not compatible with specifying + * per-tileSource overlays via the options, as those overlays will persist + * even after the tileSource is closed. + * + * @property {Boolean} [showReferenceStrip=false] + * If sequenceMode is true, then display a scrolling strip of image thumbnails for + * navigating through the images. + * + * @property {String} [referenceStripScroll='horizontal'] + * + * @property {Element} [referenceStripElement=null] + * + * @property {Number} [referenceStripHeight=null] + * + * @property {Number} [referenceStripWidth=null] + * + * @property {String} [referenceStripPosition='BOTTOM_LEFT'] + * + * @property {Number} [referenceStripSizeRatio=0.2] + * + * @property {Boolean} [collectionMode=false] + * Set to true to have the viewer arrange your TiledImages in a grid or line. + * + * @property {Number} [collectionRows=3] + * If collectionMode is true, specifies how many rows the grid should have. Use 1 to make a line. + * If collectionLayout is 'vertical', specifies how many columns instead. + * + * @property {Number} [collectionColumns=0] + * If collectionMode is true, specifies how many columns the grid should have. Use 1 to make a line. + * If collectionLayout is 'vertical', specifies how many rows instead. Ignored if collectionRows is not set to a falsy value. + * + * @property {String} [collectionLayout='horizontal'] + * If collectionMode is true, specifies whether to arrange vertically or horizontally. + * + * @property {Number} [collectionTileSize=800] + * If collectionMode is true, specifies the size, in viewport coordinates, for each TiledImage to fit into. + * The TiledImage will be centered within a square of the specified size. + * + * @property {Number} [collectionTileMargin=80] + * If collectionMode is true, specifies the margin, in viewport coordinates, between each TiledImage. + * + * @property {String|Boolean} [crossOriginPolicy=false] + * Valid values are 'Anonymous', 'use-credentials', and false. If false, canvas requests will + * not use CORS, and the canvas will be tainted. + * + * @property {Boolean} [ajaxWithCredentials=false] + * Whether to set the withCredentials XHR flag for AJAX requests. + * Note that this can be overridden at the {@link OpenSeadragon.TileSource} level. + * + * @property {Boolean} [loadTilesWithAjax=false] + * Whether to load tile data using AJAX requests. + * Note that this can be overridden at the {@link OpenSeadragon.TileSource} level. + * + * @property {Object} [ajaxHeaders={}] + * A set of headers to include when making AJAX requests for tile sources or tiles. + * + */ + + /** + * Settings for gestures generated by a pointer device. + * + * @typedef {Object} GestureSettings + * @memberof OpenSeadragon + * + * @property {Boolean} scrollToZoom + * Set to false to disable zooming on scroll gestures. + * + * @property {Boolean} clickToZoom + * Set to false to disable zooming on click gestures. + * + * @property {Boolean} dblClickToZoom + * Set to false to disable zooming on double-click gestures. Note: If set to true + * then clickToZoom should be set to false to prevent multiple zooms. + * + * @property {Boolean} pinchToZoom + * Set to false to disable zooming on pinch gestures. + * + * @property {Boolean} flickEnabled + * Set to false to disable the kinetic panning effect (flick) at the end of a drag gesture. + * + * @property {Number} flickMinSpeed + * If flickEnabled is true, the minimum speed (in pixels-per-second) required to cause the kinetic panning effect (flick) at the end of a drag gesture. + * + * @property {Number} flickMomentum + * If flickEnabled is true, a constant multiplied by the velocity to determine the distance of the kinetic panning effect (flick) at the end of a drag gesture. + * A larger value will make the flick feel "lighter", while a smaller value will make the flick feel "heavier". + * Note: springStiffness and animationTime also affect the "spring" used to stop the flick animation. + * + */ + +/** + * The names for the image resources used for the image navigation buttons. + * + * @typedef {Object} NavImages + * @memberof OpenSeadragon + * + * @property {Object} zoomIn - Images for the zoom-in button. + * @property {String} zoomIn.REST + * @property {String} zoomIn.GROUP + * @property {String} zoomIn.HOVER + * @property {String} zoomIn.DOWN + * + * @property {Object} zoomOut - Images for the zoom-out button. + * @property {String} zoomOut.REST + * @property {String} zoomOut.GROUP + * @property {String} zoomOut.HOVER + * @property {String} zoomOut.DOWN + * + * @property {Object} home - Images for the home button. + * @property {String} home.REST + * @property {String} home.GROUP + * @property {String} home.HOVER + * @property {String} home.DOWN + * + * @property {Object} fullpage - Images for the full-page button. + * @property {String} fullpage.REST + * @property {String} fullpage.GROUP + * @property {String} fullpage.HOVER + * @property {String} fullpage.DOWN + * + * @property {Object} rotateleft - Images for the rotate left button. + * @property {String} rotateleft.REST + * @property {String} rotateleft.GROUP + * @property {String} rotateleft.HOVER + * @property {String} rotateleft.DOWN + * + * @property {Object} rotateright - Images for the rotate right button. + * @property {String} rotateright.REST + * @property {String} rotateright.GROUP + * @property {String} rotateright.HOVER + * @property {String} rotateright.DOWN + * + * @property {Object} previous - Images for the previous button. + * @property {String} previous.REST + * @property {String} previous.GROUP + * @property {String} previous.HOVER + * @property {String} previous.DOWN + * + * @property {Object} next - Images for the next button. + * @property {String} next.REST + * @property {String} next.GROUP + * @property {String} next.HOVER + * @property {String} next.DOWN + * + */ + + +function OpenSeadragon( options ){ + return new OpenSeadragon.Viewer( options ); +} + +(function( $ ){ + + + /** + * The OpenSeadragon version. + * + * @member {Object} OpenSeadragon.version + * @property {String} versionStr - The version number as a string ('major.minor.revision'). + * @property {Number} major - The major version number. + * @property {Number} minor - The minor version number. + * @property {Number} revision - The revision number. + * @since 1.0.0 + */ + $.version = { + versionStr: '2.3.1', + major: parseInt('2', 10), + minor: parseInt('3', 10), + revision: parseInt('1', 10) + }; + + + /** + * Taken from jquery 1.6.1 + * [[Class]] -> type pairs + * @private + */ + var class2type = { + '[object Boolean]': 'boolean', + '[object Number]': 'number', + '[object String]': 'string', + '[object Function]': 'function', + '[object Array]': 'array', + '[object Date]': 'date', + '[object RegExp]': 'regexp', + '[object Object]': 'object' + }, + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty; + + /** + * Taken from jQuery 1.6.1 + * @function isFunction + * @memberof OpenSeadragon + * @see {@link http://www.jquery.com/ jQuery} + */ + $.isFunction = function( obj ) { + return $.type(obj) === "function"; + }; + + + /** + * Taken from jQuery 1.6.1 + * @function isArray + * @memberof OpenSeadragon + * @see {@link http://www.jquery.com/ jQuery} + */ + $.isArray = Array.isArray || function( obj ) { + return $.type(obj) === "array"; + }; + + + /** + * A crude way of determining if an object is a window. + * Taken from jQuery 1.6.1 + * @function isWindow + * @memberof OpenSeadragon + * @see {@link http://www.jquery.com/ jQuery} + */ + $.isWindow = function( obj ) { + return obj && typeof obj === "object" && "setInterval" in obj; + }; + + + /** + * Taken from jQuery 1.6.1 + * @function type + * @memberof OpenSeadragon + * @see {@link http://www.jquery.com/ jQuery} + */ + $.type = function( obj ) { + return ( obj === null ) || ( obj === undefined ) ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }; + + + /** + * Taken from jQuery 1.6.1 + * @function isPlainObject + * @memberof OpenSeadragon + * @see {@link http://www.jquery.com/ jQuery} + */ + $.isPlainObject = function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || OpenSeadragon.type(obj) !== "object" || obj.nodeType || $.isWindow( obj ) ) { + return false; + } + + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var lastKey; + for (var key in obj ) { + lastKey = key; + } + + return lastKey === undefined || hasOwn.call( obj, lastKey ); + }; + + + /** + * Taken from jQuery 1.6.1 + * @function isEmptyObject + * @memberof OpenSeadragon + * @see {@link http://www.jquery.com/ jQuery} + */ + $.isEmptyObject = function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }; + + /** + * Shim around Object.freeze. Does nothing if Object.freeze is not supported. + * @param {Object} obj The object to freeze. + * @return {Object} obj The frozen object. + */ + $.freezeObject = function(obj) { + if (Object.freeze) { + $.freezeObject = Object.freeze; + } else { + $.freezeObject = function(obj) { + return obj; + }; + } + return $.freezeObject(obj); + }; + + /** + * True if the browser supports the HTML5 canvas element + * @member {Boolean} supportsCanvas + * @memberof OpenSeadragon + */ + $.supportsCanvas = (function () { + var canvasElement = document.createElement( 'canvas' ); + return !!( $.isFunction( canvasElement.getContext ) && + canvasElement.getContext( '2d' ) ); + }()); + + /** + * Test whether the submitted canvas is tainted or not. + * @argument {Canvas} canvas The canvas to test. + * @returns {Boolean} True if the canvas is tainted. + */ + $.isCanvasTainted = function(canvas) { + var isTainted = false; + try { + // We test if the canvas is tainted by retrieving data from it. + // An exception will be raised if the canvas is tainted. + canvas.getContext('2d').getImageData(0, 0, 1, 1); + } catch (e) { + isTainted = true; + } + return isTainted; + }; + + /** + * A ratio comparing the device screen's pixel density to the canvas's backing store pixel density, + * clamped to a minimum of 1. Defaults to 1 if canvas isn't supported by the browser. + * @member {Number} pixelDensityRatio + * @memberof OpenSeadragon + */ + $.pixelDensityRatio = (function () { + if ( $.supportsCanvas ) { + var context = document.createElement('canvas').getContext('2d'); + var devicePixelRatio = window.devicePixelRatio || 1; + var backingStoreRatio = context.webkitBackingStorePixelRatio || + context.mozBackingStorePixelRatio || + context.msBackingStorePixelRatio || + context.oBackingStorePixelRatio || + context.backingStorePixelRatio || 1; + return Math.max(devicePixelRatio, 1) / backingStoreRatio; + } else { + return 1; + } + }()); + +}( OpenSeadragon )); + +/** + * This closure defines all static methods available to the OpenSeadragon + * namespace. Many, if not most, are taked directly from jQuery for use + * to simplify and reduce common programming patterns. More static methods + * from jQuery may eventually make their way into this though we are + * attempting to avoid an explicit dependency on jQuery only because + * OpenSeadragon is a broadly useful code base and would be made less broad + * by requiring jQuery fully. + * + * Some static methods have also been refactored from the original OpenSeadragon + * project. + */ +(function( $ ){ + + /** + * Taken from jQuery 1.6.1 + * @function extend + * @memberof OpenSeadragon + * @see {@link http://www.jquery.com/ jQuery} + */ + $.extend = function() { + var options, + name, + src, + copy, + copyIsArray, + clone, + target = arguments[ 0 ] || {}, + length = arguments.length, + deep = false, + i = 1; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[ 1 ] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !OpenSeadragon.isFunction( target ) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + options = arguments[ i ]; + if ( options !== null || options !== undefined ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( OpenSeadragon.isPlainObject( copy ) || ( copyIsArray = OpenSeadragon.isArray( copy ) ) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && OpenSeadragon.isArray( src ) ? src : []; + + } else { + clone = src && OpenSeadragon.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = OpenSeadragon.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; + }; + + var isIOSDevice = function () { + if (typeof navigator !== 'object') { + return false; + } + var userAgent = navigator.userAgent; + if (typeof userAgent !== 'string') { + return false; + } + return userAgent.indexOf('iPhone') !== -1 || + userAgent.indexOf('iPad') !== -1 || + userAgent.indexOf('iPod') !== -1; + }; + + $.extend( $, /** @lends OpenSeadragon */{ + /** + * The default values for the optional settings documented at {@link OpenSeadragon.Options}. + * @static + * @type {Object} + */ + DEFAULT_SETTINGS: { + //DATA SOURCE DETAILS + xmlPath: null, + tileSources: null, + tileHost: null, + initialPage: 0, + crossOriginPolicy: false, + ajaxWithCredentials: false, + loadTilesWithAjax: false, + ajaxHeaders: {}, + + //PAN AND ZOOM SETTINGS AND CONSTRAINTS + panHorizontal: true, + panVertical: true, + constrainDuringPan: false, + wrapHorizontal: false, + wrapVertical: false, + visibilityRatio: 0.5, //-> how much of the viewer can be negative space + minPixelRatio: 0.5, //->closer to 0 draws tiles meant for a higher zoom at this zoom + defaultZoomLevel: 0, + minZoomLevel: null, + maxZoomLevel: null, + homeFillsViewer: false, + + //UI RESPONSIVENESS AND FEEL + clickTimeThreshold: 300, + clickDistThreshold: 5, + dblClickTimeThreshold: 300, + dblClickDistThreshold: 20, + springStiffness: 6.5, + animationTime: 1.2, + gestureSettingsMouse: { + scrollToZoom: true, + clickToZoom: true, + dblClickToZoom: false, + pinchToZoom: false, + flickEnabled: false, + flickMinSpeed: 120, + flickMomentum: 0.25, + pinchRotate: false + }, + gestureSettingsTouch: { + scrollToZoom: false, + clickToZoom: false, + dblClickToZoom: true, + pinchToZoom: true, + flickEnabled: true, + flickMinSpeed: 120, + flickMomentum: 0.25, + pinchRotate: false + }, + gestureSettingsPen: { + scrollToZoom: false, + clickToZoom: true, + dblClickToZoom: false, + pinchToZoom: false, + flickEnabled: false, + flickMinSpeed: 120, + flickMomentum: 0.25, + pinchRotate: false + }, + gestureSettingsUnknown: { + scrollToZoom: false, + clickToZoom: false, + dblClickToZoom: true, + pinchToZoom: true, + flickEnabled: true, + flickMinSpeed: 120, + flickMomentum: 0.25, + pinchRotate: false + }, + zoomPerClick: 2, + zoomPerScroll: 1.2, + zoomPerSecond: 1.0, + blendTime: 0, + alwaysBlend: false, + autoHideControls: true, + immediateRender: false, + minZoomImageRatio: 0.9, //-> closer to 0 allows zoom out to infinity + maxZoomPixelRatio: 1.1, //-> higher allows 'over zoom' into pixels + smoothTileEdgesMinZoom: 1.1, //-> higher than maxZoomPixelRatio disables it + iOSDevice: isIOSDevice(), + pixelsPerWheelLine: 40, + autoResize: true, + preserveImageSizeOnResize: false, // requires autoResize=true + minScrollDeltaTime: 50, + + //DEFAULT CONTROL SETTINGS + showSequenceControl: true, //SEQUENCE + sequenceControlAnchor: null, //SEQUENCE + preserveViewport: false, //SEQUENCE + preserveOverlays: false, //SEQUENCE + navPrevNextWrap: false, //SEQUENCE + showNavigationControl: true, //ZOOM/HOME/FULL/ROTATION + navigationControlAnchor: null, //ZOOM/HOME/FULL/ROTATION + showZoomControl: true, //ZOOM + showHomeControl: true, //HOME + showFullPageControl: true, //FULL + showRotationControl: false, //ROTATION + controlsFadeDelay: 2000, //ZOOM/HOME/FULL/SEQUENCE + controlsFadeLength: 1500, //ZOOM/HOME/FULL/SEQUENCE + mouseNavEnabled: true, //GENERAL MOUSE INTERACTIVITY + + //VIEWPORT NAVIGATOR SETTINGS + showNavigator: false, + navigatorId: null, + navigatorPosition: null, + navigatorSizeRatio: 0.2, + navigatorMaintainSizeRatio: false, + navigatorTop: null, + navigatorLeft: null, + navigatorHeight: null, + navigatorWidth: null, + navigatorAutoResize: true, + navigatorAutoFade: true, + navigatorRotate: true, + + // INITIAL ROTATION + degrees: 0, + + // APPEARANCE + opacity: 1, + preload: false, + compositeOperation: null, + placeholderFillStyle: null, + + //REFERENCE STRIP SETTINGS + showReferenceStrip: false, + referenceStripScroll: 'horizontal', + referenceStripElement: null, + referenceStripHeight: null, + referenceStripWidth: null, + referenceStripPosition: 'BOTTOM_LEFT', + referenceStripSizeRatio: 0.2, + + //COLLECTION VISUALIZATION SETTINGS + collectionRows: 3, //or columns depending on layout + collectionColumns: 0, //columns in horizontal layout, rows in vertical layout + collectionLayout: 'horizontal', //vertical + collectionMode: false, + collectionTileSize: 800, + collectionTileMargin: 80, + + //PERFORMANCE SETTINGS + imageLoaderLimit: 0, + maxImageCacheCount: 200, + timeout: 30000, + useCanvas: true, // Use canvas element for drawing if available + + //INTERFACE RESOURCE SETTINGS + prefixUrl: "/images/", + navImages: { + zoomIn: { + REST: 'zoomin_rest.png', + GROUP: 'zoomin_grouphover.png', + HOVER: 'zoomin_hover.png', + DOWN: 'zoomin_pressed.png' + }, + zoomOut: { + REST: 'zoomout_rest.png', + GROUP: 'zoomout_grouphover.png', + HOVER: 'zoomout_hover.png', + DOWN: 'zoomout_pressed.png' + }, + home: { + REST: 'home_rest.png', + GROUP: 'home_grouphover.png', + HOVER: 'home_hover.png', + DOWN: 'home_pressed.png' + }, + fullpage: { + REST: 'fullpage_rest.png', + GROUP: 'fullpage_grouphover.png', + HOVER: 'fullpage_hover.png', + DOWN: 'fullpage_pressed.png' + }, + rotateleft: { + REST: 'rotateleft_rest.png', + GROUP: 'rotateleft_grouphover.png', + HOVER: 'rotateleft_hover.png', + DOWN: 'rotateleft_pressed.png' + }, + rotateright: { + REST: 'rotateright_rest.png', + GROUP: 'rotateright_grouphover.png', + HOVER: 'rotateright_hover.png', + DOWN: 'rotateright_pressed.png' + }, + previous: { + REST: 'previous_rest.png', + GROUP: 'previous_grouphover.png', + HOVER: 'previous_hover.png', + DOWN: 'previous_pressed.png' + }, + next: { + REST: 'next_rest.png', + GROUP: 'next_grouphover.png', + HOVER: 'next_hover.png', + DOWN: 'next_pressed.png' + } + }, + + //DEVELOPER SETTINGS + debugMode: false, + debugGridColor: ['#437AB2', '#1B9E77', '#D95F02', '#7570B3', '#E7298A', '#66A61E', '#E6AB02', '#A6761D', '#666666'] + }, + + + /** + * TODO: get rid of this. I can't see how it's required at all. Looks + * like an early legacy code artifact. + * @static + * @ignore + */ + SIGNAL: "----seadragon----", + + + /** + * Returns a function which invokes the method as if it were a method belonging to the object. + * @function + * @param {Object} object + * @param {Function} method + * @returns {Function} + */ + delegate: function( object, method ) { + return function(){ + var args = arguments; + if ( args === undefined ){ + args = []; + } + return method.apply( object, args ); + }; + }, + + + /** + * An enumeration of Browser vendors. + * @static + * @type {Object} + * @property {Number} UNKNOWN + * @property {Number} IE + * @property {Number} FIREFOX + * @property {Number} SAFARI + * @property {Number} CHROME + * @property {Number} OPERA + */ + BROWSERS: { + UNKNOWN: 0, + IE: 1, + FIREFOX: 2, + SAFARI: 3, + CHROME: 4, + OPERA: 5 + }, + + + /** + * Returns a DOM Element for the given id or element. + * @function + * @param {String|Element} element Accepts an id or element. + * @returns {Element} The element with the given id, null, or the element itself. + */ + getElement: function( element ) { + if ( typeof ( element ) == "string" ) { + element = document.getElementById( element ); + } + return element; + }, + + + /** + * Determines the position of the upper-left corner of the element. + * @function + * @param {Element|String} element - the elemenet we want the position for. + * @returns {OpenSeadragon.Point} - the position of the upper left corner of the element. + */ + getElementPosition: function( element ) { + var result = new $.Point(), + isFixed, + offsetParent; + + element = $.getElement( element ); + isFixed = $.getElementStyle( element ).position == "fixed"; + offsetParent = getOffsetParent( element, isFixed ); + + while ( offsetParent ) { + + result.x += element.offsetLeft; + result.y += element.offsetTop; + + if ( isFixed ) { + result = result.plus( $.getPageScroll() ); + } + + element = offsetParent; + isFixed = $.getElementStyle( element ).position == "fixed"; + offsetParent = getOffsetParent( element, isFixed ); + } + + return result; + }, + + + /** + * Determines the position of the upper-left corner of the element adjusted for current page and/or element scroll. + * @function + * @param {Element|String} element - the element we want the position for. + * @returns {OpenSeadragon.Point} - the position of the upper left corner of the element adjusted for current page and/or element scroll. + */ + getElementOffset: function( element ) { + element = $.getElement( element ); + + var doc = element && element.ownerDocument, + docElement, + win, + boundingRect = { top: 0, left: 0 }; + + if ( !doc ) { + return new $.Point(); + } + + docElement = doc.documentElement; + + if ( typeof element.getBoundingClientRect !== typeof undefined ) { + boundingRect = element.getBoundingClientRect(); + } + + win = ( doc == doc.window ) ? + doc : + ( doc.nodeType === 9 ) ? + doc.defaultView || doc.parentWindow : + false; + + return new $.Point( + boundingRect.left + ( win.pageXOffset || docElement.scrollLeft ) - ( docElement.clientLeft || 0 ), + boundingRect.top + ( win.pageYOffset || docElement.scrollTop ) - ( docElement.clientTop || 0 ) + ); + }, + + + /** + * Determines the height and width of the given element. + * @function + * @param {Element|String} element + * @returns {OpenSeadragon.Point} + */ + getElementSize: function( element ) { + element = $.getElement( element ); + + return new $.Point( + element.clientWidth, + element.clientHeight + ); + }, + + + /** + * Returns the CSSStyle object for the given element. + * @function + * @param {Element|String} element + * @returns {CSSStyle} + */ + getElementStyle: + document.documentElement.currentStyle ? + function( element ) { + element = $.getElement( element ); + return element.currentStyle; + } : + function( element ) { + element = $.getElement( element ); + return window.getComputedStyle( element, "" ); + }, + + /** + * Returns the property with the correct vendor prefix appended. + * @param {String} property the property name + * @returns {String} the property with the correct prefix or null if not + * supported. + */ + getCssPropertyWithVendorPrefix: function(property) { + var memo = {}; + + $.getCssPropertyWithVendorPrefix = function(property) { + if (memo[property] !== undefined) { + return memo[property]; + } + var style = document.createElement('div').style; + var result = null; + if (style[property] !== undefined) { + result = property; + } else { + var prefixes = ['Webkit', 'Moz', 'MS', 'O', + 'webkit', 'moz', 'ms', 'o']; + var suffix = $.capitalizeFirstLetter(property); + for (var i = 0; i < prefixes.length; i++) { + var prop = prefixes[i] + suffix; + if (style[prop] !== undefined) { + result = prop; + break; + } + } + } + memo[property] = result; + return result; + }; + return $.getCssPropertyWithVendorPrefix(property); + }, + + /** + * Capitalizes the first letter of a string + * @param {String} string + * @returns {String} The string with the first letter capitalized + */ + capitalizeFirstLetter: function(string) { + return string.charAt(0).toUpperCase() + string.slice(1); + }, + + /** + * Compute the modulo of a number but makes sure to always return + * a positive value. + * @param {Number} number the number to computes the modulo of + * @param {Number} modulo the modulo + * @returns {Number} the result of the modulo of number + */ + positiveModulo: function(number, modulo) { + var result = number % modulo; + if (result < 0) { + result += modulo; + } + return result; + }, + + /** + * Determines if a point is within the bounding rectangle of the given element (hit-test). + * @function + * @param {Element|String} element + * @param {OpenSeadragon.Point} point + * @returns {Boolean} + */ + pointInElement: function( element, point ) { + element = $.getElement( element ); + var offset = $.getElementOffset( element ), + size = $.getElementSize( element ); + return point.x >= offset.x && point.x < offset.x + size.x && point.y < offset.y + size.y && point.y >= offset.y; + }, + + + /** + * Gets the latest event, really only useful internally since its + * specific to IE behavior. + * @function + * @param {Event} [event] + * @returns {Event} + * @deprecated For internal use only + * @private + */ + getEvent: function( event ) { + if( event ){ + $.getEvent = function( event ) { + return event; + }; + } else { + $.getEvent = function() { + return window.event; + }; + } + return $.getEvent( event ); + }, + + + /** + * Gets the position of the mouse on the screen for a given event. + * @function + * @param {Event} [event] + * @returns {OpenSeadragon.Point} + */ + getMousePosition: function( event ) { + + if ( typeof( event.pageX ) == "number" ) { + $.getMousePosition = function( event ){ + var result = new $.Point(); + + event = $.getEvent( event ); + result.x = event.pageX; + result.y = event.pageY; + + return result; + }; + } else if ( typeof( event.clientX ) == "number" ) { + $.getMousePosition = function( event ){ + var result = new $.Point(); + + event = $.getEvent( event ); + result.x = + event.clientX + + document.body.scrollLeft + + document.documentElement.scrollLeft; + result.y = + event.clientY + + document.body.scrollTop + + document.documentElement.scrollTop; + + return result; + }; + } else { + throw new Error( + "Unknown event mouse position, no known technique." + ); + } + + return $.getMousePosition( event ); + }, + + + /** + * Determines the page's current scroll position. + * @function + * @returns {OpenSeadragon.Point} + */ + getPageScroll: function() { + var docElement = document.documentElement || {}, + body = document.body || {}; + + if ( typeof( window.pageXOffset ) == "number" ) { + $.getPageScroll = function(){ + return new $.Point( + window.pageXOffset, + window.pageYOffset + ); + }; + } else if ( body.scrollLeft || body.scrollTop ) { + $.getPageScroll = function(){ + return new $.Point( + document.body.scrollLeft, + document.body.scrollTop + ); + }; + } else if ( docElement.scrollLeft || docElement.scrollTop ) { + $.getPageScroll = function(){ + return new $.Point( + document.documentElement.scrollLeft, + document.documentElement.scrollTop + ); + }; + } else { + // We can't reassign the function yet, as there was no scroll. + return new $.Point(0, 0); + } + + return $.getPageScroll(); + }, + + /** + * Set the page scroll position. + * @function + * @returns {OpenSeadragon.Point} + */ + setPageScroll: function( scroll ) { + if ( typeof ( window.scrollTo ) !== "undefined" ) { + $.setPageScroll = function( scroll ) { + window.scrollTo( scroll.x, scroll.y ); + }; + } else { + var originalScroll = $.getPageScroll(); + if ( originalScroll.x === scroll.x && + originalScroll.y === scroll.y ) { + // We are already correctly positioned and there + // is no way to detect the correct method. + return; + } + + document.body.scrollLeft = scroll.x; + document.body.scrollTop = scroll.y; + var currentScroll = $.getPageScroll(); + if ( currentScroll.x !== originalScroll.x && + currentScroll.y !== originalScroll.y ) { + $.setPageScroll = function( scroll ) { + document.body.scrollLeft = scroll.x; + document.body.scrollTop = scroll.y; + }; + return; + } + + document.documentElement.scrollLeft = scroll.x; + document.documentElement.scrollTop = scroll.y; + currentScroll = $.getPageScroll(); + if ( currentScroll.x !== originalScroll.x && + currentScroll.y !== originalScroll.y ) { + $.setPageScroll = function( scroll ) { + document.documentElement.scrollLeft = scroll.x; + document.documentElement.scrollTop = scroll.y; + }; + return; + } + + // We can't find anything working, so we do nothing. + $.setPageScroll = function( scroll ) { + }; + } + + return $.setPageScroll( scroll ); + }, + + /** + * Determines the size of the browsers window. + * @function + * @returns {OpenSeadragon.Point} + */ + getWindowSize: function() { + var docElement = document.documentElement || {}, + body = document.body || {}; + + if ( typeof( window.innerWidth ) == 'number' ) { + $.getWindowSize = function(){ + return new $.Point( + window.innerWidth, + window.innerHeight + ); + }; + } else if ( docElement.clientWidth || docElement.clientHeight ) { + $.getWindowSize = function(){ + return new $.Point( + document.documentElement.clientWidth, + document.documentElement.clientHeight + ); + }; + } else if ( body.clientWidth || body.clientHeight ) { + $.getWindowSize = function(){ + return new $.Point( + document.body.clientWidth, + document.body.clientHeight + ); + }; + } else { + throw new Error("Unknown window size, no known technique."); + } + + return $.getWindowSize(); + }, + + + /** + * Wraps the given element in a nest of divs so that the element can + * be easily centered using CSS tables + * @function + * @param {Element|String} element + * @returns {Element} outermost wrapper element + */ + makeCenteredNode: function( element ) { + // Convert a possible ID to an actual HTMLElement + element = $.getElement( element ); + + /* + CSS tables require you to have a display:table/row/cell hierarchy so we need to create + three nested wrapper divs: + */ + + var wrappers = [ + $.makeNeutralElement( 'div' ), + $.makeNeutralElement( 'div' ), + $.makeNeutralElement( 'div' ) + ]; + + // It feels like we should be able to pass style dicts to makeNeutralElement: + $.extend(wrappers[0].style, { + display: "table", + height: "100%", + width: "100%" + }); + + $.extend(wrappers[1].style, { + display: "table-row" + }); + + $.extend(wrappers[2].style, { + display: "table-cell", + verticalAlign: "middle", + textAlign: "center" + }); + + wrappers[0].appendChild(wrappers[1]); + wrappers[1].appendChild(wrappers[2]); + wrappers[2].appendChild(element); + + return wrappers[0]; + }, + + + /** + * Creates an easily positionable element of the given type that therefor + * serves as an excellent container element. + * @function + * @param {String} tagName + * @returns {Element} + */ + makeNeutralElement: function( tagName ) { + var element = document.createElement( tagName ), + style = element.style; + + style.background = "transparent none"; + style.border = "none"; + style.margin = "0px"; + style.padding = "0px"; + style.position = "static"; + + return element; + }, + + + /** + * Returns the current milliseconds, using Date.now() if available + * @function + */ + now: function( ) { + if (Date.now) { + $.now = Date.now; + } else { + $.now = function() { + return new Date().getTime(); + }; + } + + return $.now(); + }, + + + /** + * Ensures an image is loaded correctly to support alpha transparency. + * Generally only IE has issues doing this correctly for formats like + * png. + * @function + * @param {String} src + * @returns {Element} + */ + makeTransparentImage: function( src ) { + + $.makeTransparentImage = function( src ){ + var img = $.makeNeutralElement( "img" ); + + img.src = src; + + return img; + }; + + if ( $.Browser.vendor == $.BROWSERS.IE && $.Browser.version < 7 ) { + + $.makeTransparentImage = function( src ){ + var img = $.makeNeutralElement( "img" ), + element = null; + + element = $.makeNeutralElement("span"); + element.style.display = "inline-block"; + + img.onload = function() { + element.style.width = element.style.width || img.width + "px"; + element.style.height = element.style.height || img.height + "px"; + + img.onload = null; + img = null; // to prevent memory leaks in IE + }; + + img.src = src; + element.style.filter = + "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + + src + + "', sizingMethod='scale')"; + + return element; + }; + + } + + return $.makeTransparentImage( src ); + }, + + + /** + * Sets the opacity of the specified element. + * @function + * @param {Element|String} element + * @param {Number} opacity + * @param {Boolean} [usesAlpha] + */ + setElementOpacity: function( element, opacity, usesAlpha ) { + + var ieOpacity, + ieFilter; + + element = $.getElement( element ); + + if ( usesAlpha && !$.Browser.alpha ) { + opacity = Math.round( opacity ); + } + + if ( $.Browser.opacity ) { + element.style.opacity = opacity < 1 ? opacity : ""; + } else { + if ( opacity < 1 ) { + ieOpacity = Math.round( 100 * opacity ); + ieFilter = "alpha(opacity=" + ieOpacity + ")"; + element.style.filter = ieFilter; + } else { + element.style.filter = ""; + } + } + }, + + + /** + * Sets the specified element's touch-action style attribute to 'none'. + * @function + * @param {Element|String} element + */ + setElementTouchActionNone: function( element ) { + element = $.getElement( element ); + if ( typeof element.style.touchAction !== 'undefined' ) { + element.style.touchAction = 'none'; + } else if ( typeof element.style.msTouchAction !== 'undefined' ) { + element.style.msTouchAction = 'none'; + } + }, + + + /** + * Add the specified CSS class to the element if not present. + * @function + * @param {Element|String} element + * @param {String} className + */ + addClass: function( element, className ) { + element = $.getElement( element ); + + if (!element.className) { + element.className = className; + } else if ( ( ' ' + element.className + ' ' ). + indexOf( ' ' + className + ' ' ) === -1 ) { + element.className += ' ' + className; + } + }, + + /** + * Find the first index at which an element is found in an array or -1 + * if not present. + * + * Code taken and adapted from + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf#Compatibility + * + * @function + * @param {Array} array The array from which to find the element + * @param {Object} searchElement The element to find + * @param {Number} [fromIndex=0] Index to start research. + * @returns {Number} The index of the element in the array. + */ + indexOf: function( array, searchElement, fromIndex ) { + if ( Array.prototype.indexOf ) { + this.indexOf = function( array, searchElement, fromIndex ) { + return array.indexOf( searchElement, fromIndex ); + }; + } else { + this.indexOf = function( array, searchElement, fromIndex ) { + var i, + pivot = ( fromIndex ) ? fromIndex : 0, + length; + if ( !array ) { + throw new TypeError( ); + } + + length = array.length; + if ( length === 0 || pivot >= length ) { + return -1; + } + + if ( pivot < 0 ) { + pivot = length - Math.abs( pivot ); + } + + for ( i = pivot; i < length; i++ ) { + if ( array[i] === searchElement ) { + return i; + } + } + return -1; + }; + } + return this.indexOf( array, searchElement, fromIndex ); + }, + + /** + * Remove the specified CSS class from the element. + * @function + * @param {Element|String} element + * @param {String} className + */ + removeClass: function( element, className ) { + var oldClasses, + newClasses = [], + i; + + element = $.getElement( element ); + oldClasses = element.className.split( /\s+/ ); + for ( i = 0; i < oldClasses.length; i++ ) { + if ( oldClasses[ i ] && oldClasses[ i ] !== className ) { + newClasses.push( oldClasses[ i ] ); + } + } + element.className = newClasses.join(' '); + }, + + + /** + * Adds an event listener for the given element, eventName and handler. + * @function + * @param {Element|String} element + * @param {String} eventName + * @param {Function} handler + * @param {Boolean} [useCapture] + */ + addEvent: (function () { + if ( window.addEventListener ) { + return function ( element, eventName, handler, useCapture ) { + element = $.getElement( element ); + element.addEventListener( eventName, handler, useCapture ); + }; + } else if ( window.attachEvent ) { + return function ( element, eventName, handler, useCapture ) { + element = $.getElement( element ); + element.attachEvent( 'on' + eventName, handler ); + }; + } else { + throw new Error( "No known event model." ); + } + }()), + + + /** + * Remove a given event listener for the given element, event type and + * handler. + * @function + * @param {Element|String} element + * @param {String} eventName + * @param {Function} handler + * @param {Boolean} [useCapture] + */ + removeEvent: (function () { + if ( window.removeEventListener ) { + return function ( element, eventName, handler, useCapture ) { + element = $.getElement( element ); + element.removeEventListener( eventName, handler, useCapture ); + }; + } else if ( window.detachEvent ) { + return function( element, eventName, handler, useCapture ) { + element = $.getElement( element ); + element.detachEvent( 'on' + eventName, handler ); + }; + } else { + throw new Error( "No known event model." ); + } + }()), + + + /** + * Cancels the default browser behavior had the event propagated all + * the way up the DOM to the window object. + * @function + * @param {Event} [event] + */ + cancelEvent: function( event ) { + event = $.getEvent( event ); + + if ( event.preventDefault ) { + $.cancelEvent = function( event ){ + // W3C for preventing default + event.preventDefault(); + }; + } else { + $.cancelEvent = function( event ){ + event = $.getEvent( event ); + // legacy for preventing default + event.cancel = true; + // IE for preventing default + event.returnValue = false; + }; + } + $.cancelEvent( event ); + }, + + + /** + * Stops the propagation of the event up the DOM. + * @function + * @param {Event} [event] + */ + stopEvent: function( event ) { + event = $.getEvent( event ); + + if ( event.stopPropagation ) { + // W3C for stopping propagation + $.stopEvent = function( event ){ + event.stopPropagation(); + }; + } else { + // IE for stopping propagation + $.stopEvent = function( event ){ + event = $.getEvent( event ); + event.cancelBubble = true; + }; + + } + + $.stopEvent( event ); + }, + + + /** + * Similar to OpenSeadragon.delegate, but it does not immediately call + * the method on the object, returning a function which can be called + * repeatedly to delegate the method. It also allows additonal arguments + * to be passed during construction which will be added during each + * invocation, and each invocation can add additional arguments as well. + * + * @function + * @param {Object} object + * @param {Function} method + * @param [args] any additional arguments are passed as arguments to the + * created callback + * @returns {Function} + */ + createCallback: function( object, method ) { + //TODO: This pattern is painful to use and debug. It's much cleaner + // to use pinning plus anonymous functions. Get rid of this + // pattern! + var initialArgs = [], + i; + for ( i = 2; i < arguments.length; i++ ) { + initialArgs.push( arguments[ i ] ); + } + + return function() { + var args = initialArgs.concat( [] ), + i; + for ( i = 0; i < arguments.length; i++ ) { + args.push( arguments[ i ] ); + } + + return method.apply( object, args ); + }; + }, + + + /** + * Retreives the value of a url parameter from the window.location string. + * @function + * @param {String} key + * @returns {String} The value of the url parameter or null if no param matches. + */ + getUrlParameter: function( key ) { + // eslint-disable-next-line no-use-before-define + var value = URLPARAMS[ key ]; + return value ? value : null; + }, + + /** + * Retrieves the protocol used by the url. The url can either be absolute + * or relative. + * @function + * @private + * @param {String} url The url to retrieve the protocol from. + * @return {String} The protocol (http:, https:, file:, ftp: ...) + */ + getUrlProtocol: function( url ) { + var match = url.match(/^([a-z]+:)\/\//i); + if ( match === null ) { + // Relative URL, retrive the protocol from window.location + return window.location.protocol; + } + return match[1].toLowerCase(); + }, + + /** + * Create an XHR object + * @private + * @param {type} [local] If set to true, the XHR will be file: protocol + * compatible if possible (but may raise a warning in the browser). + * @returns {XMLHttpRequest} + */ + createAjaxRequest: function( local ) { + // IE11 does not support window.ActiveXObject so we just try to + // create one to see if it is supported. + // See: http://msdn.microsoft.com/en-us/library/ie/dn423948%28v=vs.85%29.aspx + var supportActiveX; + try { + /* global ActiveXObject:true */ + supportActiveX = !!new ActiveXObject( "Microsoft.XMLHTTP" ); + } catch( e ) { + supportActiveX = false; + } + + if ( supportActiveX ) { + if ( window.XMLHttpRequest ) { + $.createAjaxRequest = function( local ) { + if ( local ) { + return new ActiveXObject( "Microsoft.XMLHTTP" ); + } + return new XMLHttpRequest(); + }; + } else { + $.createAjaxRequest = function() { + return new ActiveXObject( "Microsoft.XMLHTTP" ); + }; + } + } else if ( window.XMLHttpRequest ) { + $.createAjaxRequest = function() { + return new XMLHttpRequest(); + }; + } else { + throw new Error( "Browser doesn't support XMLHttpRequest." ); + } + return $.createAjaxRequest( local ); + }, + + /** + * Makes an AJAX request. + * @param {Object} options + * @param {String} options.url - the url to request + * @param {Function} options.success - a function to call on a successful response + * @param {Function} options.error - a function to call on when an error occurs + * @param {Object} options.headers - headers to add to the AJAX request + * @param {String} options.responseType - the response type of the the AJAX request + * @param {Boolean} [options.withCredentials=false] - whether to set the XHR's withCredentials + * @throws {Error} + * @returns {XMLHttpRequest} + */ + makeAjaxRequest: function( url, onSuccess, onError ) { + var withCredentials; + var headers; + var responseType; + + // Note that our preferred API is that you pass in a single object; the named + // arguments are for legacy support. + if( $.isPlainObject( url ) ){ + onSuccess = url.success; + onError = url.error; + withCredentials = url.withCredentials; + headers = url.headers; + responseType = url.responseType || null; + url = url.url; + } + + var protocol = $.getUrlProtocol( url ); + var request = $.createAjaxRequest( protocol === "file:" ); + + if ( !$.isFunction( onSuccess ) ) { + throw new Error( "makeAjaxRequest requires a success callback" ); + } + + request.onreadystatechange = function() { + // 4 = DONE (https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#Properties) + if ( request.readyState == 4 ) { + request.onreadystatechange = function(){}; + + // With protocols other than http/https, a successful request status is in + // the 200's on Firefox and 0 on other browsers + if ( (request.status >= 200 && request.status < 300) || + ( request.status === 0 && + protocol !== "http:" && + protocol !== "https:" )) { + onSuccess( request ); + } else { + $.console.log( "AJAX request returned %d: %s", request.status, url ); + + if ( $.isFunction( onError ) ) { + onError( request ); + } + } + } + }; + + try { + request.open( "GET", url, true ); + + if (responseType) { + request.responseType = responseType; + } + + if (headers) { + for (var headerName in headers) { + if (headers.hasOwnProperty(headerName) && headers[headerName]) { + request.setRequestHeader(headerName, headers[headerName]); + } + } + } + + if (withCredentials) { + request.withCredentials = true; + } + + request.send(null); + } catch (e) { + var msg = e.message; + + /* + IE < 10 does not support CORS and an XHR request to a different origin will fail as soon + as send() is called. This is particularly easy to miss during development and appear in + production if you use a CDN or domain sharding and the security policy is likely to break + exception handlers since any attempt to access a property of the request object will + raise an access denied TypeError inside the catch block. + + To be friendlier, we'll check for this specific error and add a documentation pointer + to point developers in the right direction. We test the exception number because IE's + error messages are localized. + */ + var oldIE = $.Browser.vendor == $.BROWSERS.IE && $.Browser.version < 10; + if ( oldIE && typeof( e.number ) != "undefined" && e.number == -2147024891 ) { + msg += "\nSee http://msdn.microsoft.com/en-us/library/ms537505(v=vs.85).aspx#xdomain"; + } + + $.console.log( "%s while making AJAX request: %s", e.name, msg ); + + request.onreadystatechange = function(){}; + + if (window.XDomainRequest) { // IE9 or IE8 might as well try to use XDomainRequest + var xdr = new XDomainRequest(); + if (xdr) { + xdr.onload = function (e) { + if ( $.isFunction( onSuccess ) ) { + onSuccess({ // Faking an xhr object + responseText: xdr.responseText, + status: 200, // XDomainRequest doesn't support status codes, so we just fake one! :/ + statusText: 'OK' + }); + } + }; + xdr.onerror = function (e) { + if ($.isFunction(onError)) { + onError({ // Faking an xhr object + responseText: xdr.responseText, + status: 444, // 444 No Response + statusText: 'An error happened. Due to an XDomainRequest deficiency we can not extract any information about this error. Upgrade your browser.' + }); + } + }; + try { + xdr.open('GET', url); + xdr.send(); + } catch (e2) { + if ( $.isFunction( onError ) ) { + onError( request, e ); + } + } + } + } else { + if ( $.isFunction( onError ) ) { + onError( request, e ); + } + } + } + + return request; + }, + + /** + * Taken from jQuery 1.6.1 + * @function + * @param {Object} options + * @param {String} options.url + * @param {Function} options.callback + * @param {String} [options.param='callback'] The name of the url parameter + * to request the jsonp provider with. + * @param {String} [options.callbackName=] The name of the callback to + * request the jsonp provider with. + */ + jsonp: function( options ){ + var script, + url = options.url, + head = document.head || + document.getElementsByTagName( "head" )[ 0 ] || + document.documentElement, + jsonpCallback = options.callbackName || 'openseadragon' + $.now(), + previous = window[ jsonpCallback ], + replace = "$1" + jsonpCallback + "$2", + callbackParam = options.param || 'callback', + callback = options.callback; + + url = url.replace( /(\=)\?(&|$)|\?\?/i, replace ); + // Add callback manually + url += (/\?/.test( url ) ? "&" : "?") + callbackParam + "=" + jsonpCallback; + + // Install callback + window[ jsonpCallback ] = function( response ) { + if ( !previous ){ + try{ + delete window[ jsonpCallback ]; + }catch(e){ + //swallow + } + } else { + window[ jsonpCallback ] = previous; + } + if( callback && $.isFunction( callback ) ){ + callback( response ); + } + }; + + script = document.createElement( "script" ); + + //TODO: having an issue with async info requests + if( undefined !== options.async || false !== options.async ){ + script.async = "async"; + } + + if ( options.scriptCharset ) { + script.charset = options.scriptCharset; + } + + script.src = url; + + // Attach handlers for all browsers + script.onload = script.onreadystatechange = function( _, isAbort ) { + + if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { + + // Handle memory leak in IE + script.onload = script.onreadystatechange = null; + + // Remove the script + if ( head && script.parentNode ) { + head.removeChild( script ); + } + + // Dereference the script + script = undefined; + } + }; + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709 and #4378). + head.insertBefore( script, head.firstChild ); + + }, + + + /** + * Fully deprecated. Will throw an error. + * @function + * @deprecated use {@link OpenSeadragon.Viewer#open} + */ + createFromDZI: function() { + throw "OpenSeadragon.createFromDZI is deprecated, use Viewer.open."; + }, + + /** + * Parses an XML string into a DOM Document. + * @function + * @param {String} string + * @returns {Document} + */ + parseXml: function( string ) { + if ( window.DOMParser ) { + + $.parseXml = function( string ) { + var xmlDoc = null, + parser; + + parser = new DOMParser(); + xmlDoc = parser.parseFromString( string, "text/xml" ); + return xmlDoc; + }; + + } else if ( window.ActiveXObject ) { + + $.parseXml = function( string ) { + var xmlDoc = null; + + xmlDoc = new ActiveXObject( "Microsoft.XMLDOM" ); + xmlDoc.async = false; + xmlDoc.loadXML( string ); + return xmlDoc; + }; + + } else { + throw new Error( "Browser doesn't support XML DOM." ); + } + + return $.parseXml( string ); + }, + + /** + * Parses a JSON string into a Javascript object. + * @function + * @param {String} string + * @returns {Object} + */ + parseJSON: function(string) { + if (window.JSON && window.JSON.parse) { + $.parseJSON = window.JSON.parse; + } else { + // Should only be used by IE8 in non standards mode + $.parseJSON = function(string) { + /*jshint evil:true*/ + //eslint-disable-next-line no-eval + return eval('(' + string + ')'); + }; + } + return $.parseJSON(string); + }, + + /** + * Reports whether the image format is supported for tiling in this + * version. + * @function + * @param {String} [extension] + * @returns {Boolean} + */ + imageFormatSupported: function( extension ) { + extension = extension ? extension : ""; + // eslint-disable-next-line no-use-before-define + return !!FILEFORMATS[ extension.toLowerCase() ]; + } + + }); + + + /** + * The current browser vendor, version, and related information regarding detected features. + * @member {Object} Browser + * @memberof OpenSeadragon + * @static + * @type {Object} + * @property {OpenSeadragon.BROWSERS} vendor - One of the {@link OpenSeadragon.BROWSERS} enumeration values. + * @property {Number} version + * @property {Boolean} alpha - Does the browser support image alpha transparency. + */ + $.Browser = { + vendor: $.BROWSERS.UNKNOWN, + version: 0, + alpha: true + }; + + + var FILEFORMATS = { + "bmp": false, + "jpeg": true, + "jpg": true, + "png": true, + "tif": false, + "wdp": false + }, + URLPARAMS = {}; + + (function() { + //A small auto-executing routine to determine the browser vendor, + //version and supporting feature sets. + var ver = navigator.appVersion, + ua = navigator.userAgent, + regex; + + //console.error( 'appName: ' + navigator.appName ); + //console.error( 'appVersion: ' + navigator.appVersion ); + //console.error( 'userAgent: ' + navigator.userAgent ); + + switch( navigator.appName ){ + case "Microsoft Internet Explorer": + if( !!window.attachEvent && + !!window.ActiveXObject ) { + + $.Browser.vendor = $.BROWSERS.IE; + $.Browser.version = parseFloat( + ua.substring( + ua.indexOf( "MSIE" ) + 5, + ua.indexOf( ";", ua.indexOf( "MSIE" ) ) ) + ); + } + break; + case "Netscape": + if (window.addEventListener) { + if ( ua.indexOf( "Firefox" ) >= 0 ) { + $.Browser.vendor = $.BROWSERS.FIREFOX; + $.Browser.version = parseFloat( + ua.substring( ua.indexOf( "Firefox" ) + 8 ) + ); + } else if ( ua.indexOf( "Safari" ) >= 0 ) { + $.Browser.vendor = ua.indexOf( "Chrome" ) >= 0 ? + $.BROWSERS.CHROME : + $.BROWSERS.SAFARI; + $.Browser.version = parseFloat( + ua.substring( + ua.substring( 0, ua.indexOf( "Safari" ) ).lastIndexOf( "/" ) + 1, + ua.indexOf( "Safari" ) + ) + ); + } else { + regex = new RegExp( "Trident/.*rv:([0-9]{1,}[.0-9]{0,})"); + if ( regex.exec( ua ) !== null ) { + $.Browser.vendor = $.BROWSERS.IE; + $.Browser.version = parseFloat( RegExp.$1 ); + } + } + } + break; + case "Opera": + $.Browser.vendor = $.BROWSERS.OPERA; + $.Browser.version = parseFloat( ver ); + break; + } + + // ignore '?' portion of query string + var query = window.location.search.substring( 1 ), + parts = query.split('&'), + part, + sep, + i; + + for ( i = 0; i < parts.length; i++ ) { + part = parts[ i ]; + sep = part.indexOf( '=' ); + + if ( sep > 0 ) { + URLPARAMS[ part.substring( 0, sep ) ] = + decodeURIComponent( part.substring( sep + 1 ) ); + } + } + + //determine if this browser supports image alpha transparency + $.Browser.alpha = !( + ( + $.Browser.vendor == $.BROWSERS.IE && + $.Browser.version < 9 + ) || ( + $.Browser.vendor == $.BROWSERS.CHROME && + $.Browser.version < 2 + ) + ); + + //determine if this browser supports element.style.opacity + $.Browser.opacity = !( + $.Browser.vendor == $.BROWSERS.IE && + $.Browser.version < 9 + ); + + })(); + + + //TODO: $.console is often used inside a try/catch block which generally + // prevents allowings errors to occur with detection until a debugger + // is attached. Although I've been guilty of the same anti-pattern + // I eventually was convinced that errors should naturally propogate in + // all but the most special cases. + /** + * A convenient alias for console when available, and a simple null + * function when console is unavailable. + * @static + * @private + */ + var nullfunction = function( msg ){ + //document.location.hash = msg; + }; + + $.console = window.console || { + log: nullfunction, + debug: nullfunction, + info: nullfunction, + warn: nullfunction, + error: nullfunction, + assert: nullfunction + }; + + + // Adding support for HTML5's requestAnimationFrame as suggested by acdha. + // Implementation taken from matt synder's post here: + // http://mattsnider.com/cross-browser-and-legacy-supported-requestframeanimation/ + (function( w ) { + + // most browsers have an implementation + var requestAnimationFrame = w.requestAnimationFrame || + w.mozRequestAnimationFrame || + w.webkitRequestAnimationFrame || + w.msRequestAnimationFrame; + + var cancelAnimationFrame = w.cancelAnimationFrame || + w.mozCancelAnimationFrame || + w.webkitCancelAnimationFrame || + w.msCancelAnimationFrame; + + // polyfill, when necessary + if ( requestAnimationFrame && cancelAnimationFrame ) { + // We can't assign these window methods directly to $ because they + // expect their "this" to be "window", so we call them in wrappers. + $.requestAnimationFrame = function(){ + return requestAnimationFrame.apply( w, arguments ); + }; + $.cancelAnimationFrame = function(){ + return cancelAnimationFrame.apply( w, arguments ); + }; + } else { + var aAnimQueue = [], + processing = [], + iRequestId = 0, + iIntervalId; + + // create a mock requestAnimationFrame function + $.requestAnimationFrame = function( callback ) { + aAnimQueue.push( [ ++iRequestId, callback ] ); + + if ( !iIntervalId ) { + iIntervalId = setInterval( function() { + if ( aAnimQueue.length ) { + var time = $.now(); + // Process all of the currently outstanding frame + // requests, but none that get added during the + // processing. + // Swap the arrays so we don't have to create a new + // array every frame. + var temp = processing; + processing = aAnimQueue; + aAnimQueue = temp; + while ( processing.length ) { + processing.shift()[ 1 ]( time ); + } + } else { + // don't continue the interval, if unnecessary + clearInterval( iIntervalId ); + iIntervalId = undefined; + } + }, 1000 / 50); // estimating support for 50 frames per second + } + + return iRequestId; + }; + + // create a mock cancelAnimationFrame function + $.cancelAnimationFrame = function( requestId ) { + // find the request ID and remove it + var i, j; + for ( i = 0, j = aAnimQueue.length; i < j; i += 1 ) { + if ( aAnimQueue[ i ][ 0 ] === requestId ) { + aAnimQueue.splice( i, 1 ); + return; + } + } + + // If it's not in the queue, it may be in the set we're currently + // processing (if cancelAnimationFrame is called from within a + // requestAnimationFrame callback). + for ( i = 0, j = processing.length; i < j; i += 1 ) { + if ( processing[ i ][ 0 ] === requestId ) { + processing.splice( i, 1 ); + return; + } + } + }; + } + })( window ); + + /** + * @private + * @inner + * @function + * @param {Element} element + * @param {Boolean} [isFixed] + * @returns {Element} + */ + function getOffsetParent( element, isFixed ) { + if ( isFixed && element != document.body ) { + return document.body; + } else { + return element.offsetParent; + } + } + +}(OpenSeadragon)); + + +// Universal Module Definition, supports CommonJS, AMD and simple script tag +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // expose as amd module + define([], factory); + } else if (typeof module === 'object' && module.exports) { + // expose as commonjs module + module.exports = factory(); + } else { + // expose as window.OpenSeadragon + root.OpenSeadragon = factory(); + } +}(this, function () { + return OpenSeadragon; +})); + +/* + * OpenSeadragon - full-screen support functions + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ) { + /** + * Determine native full screen support we can get from the browser. + * @member fullScreenApi + * @memberof OpenSeadragon + * @type {object} + * @property {Boolean} supportsFullScreen Return true if full screen API is supported. + * @property {Function} isFullScreen Return true if currently in full screen mode. + * @property {Function} getFullScreenElement Return the element currently in full screen mode. + * @property {Function} requestFullScreen Make a request to go in full screen mode. + * @property {Function} exitFullScreen Make a request to exit full screen mode. + * @property {Function} cancelFullScreen Deprecated, use exitFullScreen instead. + * @property {String} fullScreenEventName Event fired when the full screen mode change. + * @property {String} fullScreenErrorEventName Event fired when a request to go + * in full screen mode failed. + */ + var fullScreenApi = { + supportsFullScreen: false, + isFullScreen: function() { return false; }, + getFullScreenElement: function() { return null; }, + requestFullScreen: function() {}, + exitFullScreen: function() {}, + cancelFullScreen: function() {}, + fullScreenEventName: '', + fullScreenErrorEventName: '' + }; + + // check for native support + if ( document.exitFullscreen ) { + // W3C standard + fullScreenApi.supportsFullScreen = true; + fullScreenApi.getFullScreenElement = function() { + return document.fullscreenElement; + }; + fullScreenApi.requestFullScreen = function( element ) { + return element.requestFullscreen(); + }; + fullScreenApi.exitFullScreen = function() { + document.exitFullscreen(); + }; + fullScreenApi.fullScreenEventName = "fullscreenchange"; + fullScreenApi.fullScreenErrorEventName = "fullscreenerror"; + } else if ( document.msExitFullscreen ) { + // IE 11 + fullScreenApi.supportsFullScreen = true; + fullScreenApi.getFullScreenElement = function() { + return document.msFullscreenElement; + }; + fullScreenApi.requestFullScreen = function( element ) { + return element.msRequestFullscreen(); + }; + fullScreenApi.exitFullScreen = function() { + document.msExitFullscreen(); + }; + fullScreenApi.fullScreenEventName = "MSFullscreenChange"; + fullScreenApi.fullScreenErrorEventName = "MSFullscreenError"; + } else if ( document.webkitExitFullscreen ) { + // Recent webkit + fullScreenApi.supportsFullScreen = true; + fullScreenApi.getFullScreenElement = function() { + return document.webkitFullscreenElement; + }; + fullScreenApi.requestFullScreen = function( element ) { + return element.webkitRequestFullscreen(); + }; + fullScreenApi.exitFullScreen = function() { + document.webkitExitFullscreen(); + }; + fullScreenApi.fullScreenEventName = "webkitfullscreenchange"; + fullScreenApi.fullScreenErrorEventName = "webkitfullscreenerror"; + } else if ( document.webkitCancelFullScreen ) { + // Old webkit + fullScreenApi.supportsFullScreen = true; + fullScreenApi.getFullScreenElement = function() { + return document.webkitCurrentFullScreenElement; + }; + fullScreenApi.requestFullScreen = function( element ) { + return element.webkitRequestFullScreen(); + }; + fullScreenApi.exitFullScreen = function() { + document.webkitCancelFullScreen(); + }; + fullScreenApi.fullScreenEventName = "webkitfullscreenchange"; + fullScreenApi.fullScreenErrorEventName = "webkitfullscreenerror"; + } else if ( document.mozCancelFullScreen ) { + // Firefox + fullScreenApi.supportsFullScreen = true; + fullScreenApi.getFullScreenElement = function() { + return document.mozFullScreenElement; + }; + fullScreenApi.requestFullScreen = function( element ) { + return element.mozRequestFullScreen(); + }; + fullScreenApi.exitFullScreen = function() { + document.mozCancelFullScreen(); + }; + fullScreenApi.fullScreenEventName = "mozfullscreenchange"; + fullScreenApi.fullScreenErrorEventName = "mozfullscreenerror"; + } + fullScreenApi.isFullScreen = function() { + return fullScreenApi.getFullScreenElement() !== null; + }; + fullScreenApi.cancelFullScreen = function() { + $.console.error("cancelFullScreen is deprecated. Use exitFullScreen instead."); + fullScreenApi.exitFullScreen(); + }; + + // export api + $.extend( $, fullScreenApi ); + +})( OpenSeadragon ); + +/* + * OpenSeadragon - EventSource + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function($){ + +/** + * Event handler method signature used by all OpenSeadragon events. + * + * @callback EventHandler + * @memberof OpenSeadragon + * @param {Object} event - See individual events for event-specific properties. + */ + + +/** + * @class EventSource + * @classdesc For use by classes which want to support custom, non-browser events. + * + * @memberof OpenSeadragon + */ +$.EventSource = function() { + this.events = {}; +}; + +/** @lends OpenSeadragon.EventSource.prototype */ +$.EventSource.prototype = { + + /** + * Add an event handler to be triggered only once (or a given number of times) + * for a given event. + * @function + * @param {String} eventName - Name of event to register. + * @param {OpenSeadragon.EventHandler} handler - Function to call when event + * is triggered. + * @param {Object} [userData=null] - Arbitrary object to be passed unchanged + * to the handler. + * @param {Number} [times=1] - The number of times to handle the event + * before removing it. + */ + addOnceHandler: function(eventName, handler, userData, times) { + var self = this; + times = times || 1; + var count = 0; + var onceHandler = function(event) { + count++; + if (count === times) { + self.removeHandler(eventName, onceHandler); + } + handler(event); + }; + this.addHandler(eventName, onceHandler, userData); + }, + + /** + * Add an event handler for a given event. + * @function + * @param {String} eventName - Name of event to register. + * @param {OpenSeadragon.EventHandler} handler - Function to call when event is triggered. + * @param {Object} [userData=null] - Arbitrary object to be passed unchanged to the handler. + */ + addHandler: function ( eventName, handler, userData ) { + var events = this.events[ eventName ]; + if ( !events ) { + this.events[ eventName ] = events = []; + } + if ( handler && $.isFunction( handler ) ) { + events[ events.length ] = { handler: handler, userData: userData || null }; + } + }, + + /** + * Remove a specific event handler for a given event. + * @function + * @param {String} eventName - Name of event for which the handler is to be removed. + * @param {OpenSeadragon.EventHandler} handler - Function to be removed. + */ + removeHandler: function ( eventName, handler ) { + var events = this.events[ eventName ], + handlers = [], + i; + if ( !events ) { + return; + } + if ( $.isArray( events ) ) { + for ( i = 0; i < events.length; i++ ) { + if ( events[i].handler !== handler ) { + handlers.push( events[ i ] ); + } + } + this.events[ eventName ] = handlers; + } + }, + + + /** + * Remove all event handlers for a given event type. If no type is given all + * event handlers for every event type are removed. + * @function + * @param {String} eventName - Name of event for which all handlers are to be removed. + */ + removeAllHandlers: function( eventName ) { + if ( eventName ){ + this.events[ eventName ] = []; + } else{ + for ( var eventType in this.events ) { + this.events[ eventType ] = []; + } + } + }, + + /** + * Get a function which iterates the list of all handlers registered for a given event, calling the handler for each. + * @function + * @param {String} eventName - Name of event to get handlers for. + */ + getHandler: function ( eventName ) { + var events = this.events[ eventName ]; + if ( !events || !events.length ) { + return null; + } + events = events.length === 1 ? + [ events[ 0 ] ] : + Array.apply( null, events ); + return function ( source, args ) { + var i, + length = events.length; + for ( i = 0; i < length; i++ ) { + if ( events[ i ] ) { + args.eventSource = source; + args.userData = events[ i ].userData; + events[ i ].handler( args ); + } + } + }; + }, + + /** + * Trigger an event, optionally passing additional information. + * @function + * @param {String} eventName - Name of event to register. + * @param {Object} eventArgs - Event-specific data. + */ + raiseEvent: function( eventName, eventArgs ) { + //uncomment if you want to get a log of all events + //$.console.log( eventName ); + var handler = this.getHandler( eventName ); + + if ( handler ) { + if ( !eventArgs ) { + eventArgs = {}; + } + + handler( this, eventArgs ); + } + } +}; + +}( OpenSeadragon )); + +/* + * OpenSeadragon - MouseTracker + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function ( $ ) { + + // All MouseTracker instances + var MOUSETRACKERS = []; + + // dictionary from hash to private properties + var THIS = {}; + + + /** + * @class MouseTracker + * @classdesc Provides simplified handling of common pointer device (mouse, touch, pen, etc.) gestures + * and keyboard events on a specified element. + * @memberof OpenSeadragon + * @param {Object} options + * Allows configurable properties to be entirely specified by passing + * an options object to the constructor. The constructor also supports + * the original positional arguments 'element', 'clickTimeThreshold', + * and 'clickDistThreshold' in that order. + * @param {Element|String} options.element + * A reference to an element or an element id for which the pointer/key + * events will be monitored. + * @param {Boolean} [options.startDisabled=false] + * If true, event tracking on the element will not start until + * {@link OpenSeadragon.MouseTracker.setTracking|setTracking} is called. + * @param {Number} options.clickTimeThreshold + * The number of milliseconds within which a pointer down-up event combination + * will be treated as a click gesture. + * @param {Number} options.clickDistThreshold + * The maximum distance allowed between a pointer down event and a pointer up event + * to be treated as a click gesture. + * @param {Number} options.dblClickTimeThreshold + * The number of milliseconds within which two pointer down-up event combinations + * will be treated as a double-click gesture. + * @param {Number} options.dblClickDistThreshold + * The maximum distance allowed between two pointer click events + * to be treated as a click gesture. + * @param {Number} [options.stopDelay=50] + * The number of milliseconds without pointer move before the stop + * event is fired. + * @param {OpenSeadragon.EventHandler} [options.enterHandler=null] + * An optional handler for pointer enter. + * @param {OpenSeadragon.EventHandler} [options.exitHandler=null] + * An optional handler for pointer exit. + * @param {OpenSeadragon.EventHandler} [options.pressHandler=null] + * An optional handler for pointer press. + * @param {OpenSeadragon.EventHandler} [options.nonPrimaryPressHandler=null] + * An optional handler for pointer non-primary button press. + * @param {OpenSeadragon.EventHandler} [options.releaseHandler=null] + * An optional handler for pointer release. + * @param {OpenSeadragon.EventHandler} [options.nonPrimaryReleaseHandler=null] + * An optional handler for pointer non-primary button release. + * @param {OpenSeadragon.EventHandler} [options.moveHandler=null] + * An optional handler for pointer move. + * @param {OpenSeadragon.EventHandler} [options.scrollHandler=null] + * An optional handler for mouse wheel scroll. + * @param {OpenSeadragon.EventHandler} [options.clickHandler=null] + * An optional handler for pointer click. + * @param {OpenSeadragon.EventHandler} [options.dblClickHandler=null] + * An optional handler for pointer double-click. + * @param {OpenSeadragon.EventHandler} [options.dragHandler=null] + * An optional handler for the drag gesture. + * @param {OpenSeadragon.EventHandler} [options.dragEndHandler=null] + * An optional handler for after a drag gesture. + * @param {OpenSeadragon.EventHandler} [options.pinchHandler=null] + * An optional handler for the pinch gesture. + * @param {OpenSeadragon.EventHandler} [options.keyDownHandler=null] + * An optional handler for keydown. + * @param {OpenSeadragon.EventHandler} [options.keyUpHandler=null] + * An optional handler for keyup. + * @param {OpenSeadragon.EventHandler} [options.keyHandler=null] + * An optional handler for keypress. + * @param {OpenSeadragon.EventHandler} [options.focusHandler=null] + * An optional handler for focus. + * @param {OpenSeadragon.EventHandler} [options.blurHandler=null] + * An optional handler for blur. + * @param {Object} [options.userData=null] + * Arbitrary object to be passed unchanged to any attached handler methods. + */ + $.MouseTracker = function ( options ) { + + MOUSETRACKERS.push( this ); + + var args = arguments; + + if ( !$.isPlainObject( options ) ) { + options = { + element: args[ 0 ], + clickTimeThreshold: args[ 1 ], + clickDistThreshold: args[ 2 ] + }; + } + + this.hash = Math.random(); // An unique hash for this tracker. + /** + * The element for which pointer events are being monitored. + * @member {Element} element + * @memberof OpenSeadragon.MouseTracker# + */ + this.element = $.getElement( options.element ); + /** + * The number of milliseconds within which a pointer down-up event combination + * will be treated as a click gesture. + * @member {Number} clickTimeThreshold + * @memberof OpenSeadragon.MouseTracker# + */ + this.clickTimeThreshold = options.clickTimeThreshold || $.DEFAULT_SETTINGS.clickTimeThreshold; + /** + * The maximum distance allowed between a pointer down event and a pointer up event + * to be treated as a click gesture. + * @member {Number} clickDistThreshold + * @memberof OpenSeadragon.MouseTracker# + */ + this.clickDistThreshold = options.clickDistThreshold || $.DEFAULT_SETTINGS.clickDistThreshold; + /** + * The number of milliseconds within which two pointer down-up event combinations + * will be treated as a double-click gesture. + * @member {Number} dblClickTimeThreshold + * @memberof OpenSeadragon.MouseTracker# + */ + this.dblClickTimeThreshold = options.dblClickTimeThreshold || $.DEFAULT_SETTINGS.dblClickTimeThreshold; + /** + * The maximum distance allowed between two pointer click events + * to be treated as a click gesture. + * @member {Number} clickDistThreshold + * @memberof OpenSeadragon.MouseTracker# + */ + this.dblClickDistThreshold = options.dblClickDistThreshold || $.DEFAULT_SETTINGS.dblClickDistThreshold; + /*eslint-disable no-multi-spaces*/ + this.userData = options.userData || null; + this.stopDelay = options.stopDelay || 50; + + this.enterHandler = options.enterHandler || null; + this.exitHandler = options.exitHandler || null; + this.pressHandler = options.pressHandler || null; + this.nonPrimaryPressHandler = options.nonPrimaryPressHandler || null; + this.releaseHandler = options.releaseHandler || null; + this.nonPrimaryReleaseHandler = options.nonPrimaryReleaseHandler || null; + this.moveHandler = options.moveHandler || null; + this.scrollHandler = options.scrollHandler || null; + this.clickHandler = options.clickHandler || null; + this.dblClickHandler = options.dblClickHandler || null; + this.dragHandler = options.dragHandler || null; + this.dragEndHandler = options.dragEndHandler || null; + this.pinchHandler = options.pinchHandler || null; + this.stopHandler = options.stopHandler || null; + this.keyDownHandler = options.keyDownHandler || null; + this.keyUpHandler = options.keyUpHandler || null; + this.keyHandler = options.keyHandler || null; + this.focusHandler = options.focusHandler || null; + this.blurHandler = options.blurHandler || null; + /*eslint-enable no-multi-spaces*/ + + //Store private properties in a scope sealed hash map + var _this = this; + + /** + * @private + * @property {Boolean} tracking + * Are we currently tracking pointer events for this element. + */ + THIS[ this.hash ] = { + click: function ( event ) { onClick( _this, event ); }, + dblclick: function ( event ) { onDblClick( _this, event ); }, + keydown: function ( event ) { onKeyDown( _this, event ); }, + keyup: function ( event ) { onKeyUp( _this, event ); }, + keypress: function ( event ) { onKeyPress( _this, event ); }, + focus: function ( event ) { onFocus( _this, event ); }, + blur: function ( event ) { onBlur( _this, event ); }, + + wheel: function ( event ) { onWheel( _this, event ); }, + mousewheel: function ( event ) { onMouseWheel( _this, event ); }, + DOMMouseScroll: function ( event ) { onMouseWheel( _this, event ); }, + MozMousePixelScroll: function ( event ) { onMouseWheel( _this, event ); }, + + mouseenter: function ( event ) { onMouseEnter( _this, event ); }, // Used on IE8 only + mouseleave: function ( event ) { onMouseLeave( _this, event ); }, // Used on IE8 only + mouseover: function ( event ) { onMouseOver( _this, event ); }, + mouseout: function ( event ) { onMouseOut( _this, event ); }, + mousedown: function ( event ) { onMouseDown( _this, event ); }, + mouseup: function ( event ) { onMouseUp( _this, event ); }, + mouseupcaptured: function ( event ) { onMouseUpCaptured( _this, event ); }, + mousemove: function ( event ) { onMouseMove( _this, event ); }, + mousemovecaptured: function ( event ) { onMouseMoveCaptured( _this, event ); }, + + touchstart: function ( event ) { onTouchStart( _this, event ); }, + touchend: function ( event ) { onTouchEnd( _this, event ); }, + touchendcaptured: function ( event ) { onTouchEndCaptured( _this, event ); }, + touchmove: function ( event ) { onTouchMove( _this, event ); }, + touchmovecaptured: function ( event ) { onTouchMoveCaptured( _this, event ); }, + touchcancel: function ( event ) { onTouchCancel( _this, event ); }, + + gesturestart: function ( event ) { onGestureStart( _this, event ); }, + gesturechange: function ( event ) { onGestureChange( _this, event ); }, + + pointerover: function ( event ) { onPointerOver( _this, event ); }, + MSPointerOver: function ( event ) { onPointerOver( _this, event ); }, + pointerout: function ( event ) { onPointerOut( _this, event ); }, + MSPointerOut: function ( event ) { onPointerOut( _this, event ); }, + pointerdown: function ( event ) { onPointerDown( _this, event ); }, + MSPointerDown: function ( event ) { onPointerDown( _this, event ); }, + pointerup: function ( event ) { onPointerUp( _this, event ); }, + MSPointerUp: function ( event ) { onPointerUp( _this, event ); }, + pointermove: function ( event ) { onPointerMove( _this, event ); }, + MSPointerMove: function ( event ) { onPointerMove( _this, event ); }, + pointercancel: function ( event ) { onPointerCancel( _this, event ); }, + MSPointerCancel: function ( event ) { onPointerCancel( _this, event ); }, + pointerupcaptured: function ( event ) { onPointerUpCaptured( _this, event ); }, + pointermovecaptured: function ( event ) { onPointerMoveCaptured( _this, event ); }, + + tracking: false, + + // Active pointers lists. Array of GesturePointList objects, one for each pointer device type. + // GesturePointList objects are added each time a pointer is tracked by a new pointer device type (see getActivePointersListByType()). + // Active pointers are any pointer being tracked for this element which are in the hit-test area + // of the element (for hover-capable devices) and/or have contact or a button press initiated in the element. + activePointersLists: [], + + // Tracking for double-click gesture + lastClickPos: null, + dblClickTimeOut: null, + + // Tracking for pinch gesture + pinchGPoints: [], + lastPinchDist: 0, + currentPinchDist: 0, + lastPinchCenter: null, + currentPinchCenter: null + }; + + if ( !options.startDisabled ) { + this.setTracking( true ); + } + }; + + /** @lends OpenSeadragon.MouseTracker.prototype */ + $.MouseTracker.prototype = { + + /** + * Clean up any events or objects created by the tracker. + * @function + */ + destroy: function () { + var i; + + stopTracking( this ); + this.element = null; + + for ( i = 0; i < MOUSETRACKERS.length; i++ ) { + if ( MOUSETRACKERS[ i ] === this ) { + MOUSETRACKERS.splice( i, 1 ); + break; + } + } + + THIS[ this.hash ] = null; + delete THIS[ this.hash ]; + }, + + /** + * Are we currently tracking events on this element. + * @deprecated Just use this.tracking + * @function + * @returns {Boolean} Are we currently tracking events on this element. + */ + isTracking: function () { + return THIS[ this.hash ].tracking; + }, + + /** + * Enable or disable whether or not we are tracking events on this element. + * @function + * @param {Boolean} track True to start tracking, false to stop tracking. + * @returns {OpenSeadragon.MouseTracker} Chainable. + */ + setTracking: function ( track ) { + if ( track ) { + startTracking( this ); + } else { + stopTracking( this ); + } + //chain + return this; + }, + + /** + * Returns the {@link OpenSeadragon.MouseTracker.GesturePointList|GesturePointList} for all but the given pointer device type. + * @function + * @param {String} type - The pointer device type: "mouse", "touch", "pen", etc. + * @returns {Array.} + */ + getActivePointersListsExceptType: function ( type ) { + var delegate = THIS[ this.hash ]; + var listArray = []; + + for (var i = 0; i < delegate.activePointersLists.length; ++i) { + if (delegate.activePointersLists[i].type !== type) { + listArray.push(delegate.activePointersLists[i]); + } + } + + return listArray; + }, + + /** + * Returns the {@link OpenSeadragon.MouseTracker.GesturePointList|GesturePointList} for the given pointer device type, + * creating and caching a new {@link OpenSeadragon.MouseTracker.GesturePointList|GesturePointList} if one doesn't already exist for the type. + * @function + * @param {String} type - The pointer device type: "mouse", "touch", "pen", etc. + * @returns {OpenSeadragon.MouseTracker.GesturePointList} + */ + getActivePointersListByType: function ( type ) { + var delegate = THIS[ this.hash ], + i, + len = delegate.activePointersLists.length, + list; + + for ( i = 0; i < len; i++ ) { + if ( delegate.activePointersLists[ i ].type === type ) { + return delegate.activePointersLists[ i ]; + } + } + + list = new $.MouseTracker.GesturePointList( type ); + delegate.activePointersLists.push( list ); + return list; + }, + + /** + * Returns the total number of pointers currently active on the tracked element. + * @function + * @returns {Number} + */ + getActivePointerCount: function () { + var delegate = THIS[ this.hash ], + i, + len = delegate.activePointersLists.length, + count = 0; + + for ( i = 0; i < len; i++ ) { + count += delegate.activePointersLists[ i ].getLength(); + } + + return count; + }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Number} event.pointers + * Number of pointers (all types) active in the tracked element. + * @param {Boolean} event.insideElementPressed + * True if the left mouse button is currently being pressed and was + * initiated inside the tracked element, otherwise false. + * @param {Boolean} event.buttonDownAny + * Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + enterHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Number} event.pointers + * Number of pointers (all types) active in the tracked element. + * @param {Boolean} event.insideElementPressed + * True if the left mouse button is currently being pressed and was + * initiated inside the tracked element, otherwise false. + * @param {Boolean} event.buttonDownAny + * Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + exitHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + pressHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.button + * Button which caused the event. + * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + nonPrimaryPressHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Boolean} event.insideElementPressed + * True if the left mouse button is currently being pressed and was + * initiated inside the tracked element, otherwise false. + * @param {Boolean} event.insideElementReleased + * True if the cursor inside the tracked element when the button was released. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + releaseHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.button + * Button which caused the event. + * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + nonPrimaryReleaseHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + moveHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.scroll + * The scroll delta for the event. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. Touch devices no longer generate scroll event. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + scrollHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Boolean} event.quick + * True only if the clickDistThreshold and clickTimeThreshold are both passed. Useful for ignoring drag events. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + clickHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + dblClickHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {OpenSeadragon.Point} event.delta + * The x,y components of the difference between the current position and the last drag event position. Useful for ignoring or weighting the events. + * @param {Number} event.speed + * Current computed speed, in pixels per second. + * @param {Number} event.direction + * Current computed direction, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + dragHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.speed + * Speed at the end of a drag gesture, in pixels per second. + * @param {Number} event.direction + * Direction at the end of a drag gesture, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + dragEndHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {Array.} event.gesturePoints + * Gesture points associated with the gesture. Velocity data can be found here. + * @param {OpenSeadragon.Point} event.lastCenter + * The previous center point of the two pinch contact points relative to the tracked element. + * @param {OpenSeadragon.Point} event.center + * The center point of the two pinch contact points relative to the tracked element. + * @param {Number} event.lastDistance + * The previous distance between the two pinch contact points in CSS pixels. + * @param {Number} event.distance + * The distance between the two pinch contact points in CSS pixels. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + pinchHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + stopHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {Number} event.keyCode + * The key code that was pressed. + * @param {Boolean} event.ctrl + * True if the ctrl key was pressed during this event. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.alt + * True if the alt key was pressed during this event. + * @param {Boolean} event.meta + * True if the meta key was pressed during this event. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + keyDownHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {Number} event.keyCode + * The key code that was pressed. + * @param {Boolean} event.ctrl + * True if the ctrl key was pressed during this event. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.alt + * True if the alt key was pressed during this event. + * @param {Boolean} event.meta + * True if the meta key was pressed during this event. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + keyUpHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {Number} event.keyCode + * The key code that was pressed. + * @param {Boolean} event.ctrl + * True if the ctrl key was pressed during this event. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.alt + * True if the alt key was pressed during this event. + * @param {Boolean} event.meta + * True if the meta key was pressed during this event. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + keyHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + focusHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + blurHandler: function () { } + }; + + /** + * Resets all active mousetrakers. (Added to patch issue #697 "Mouse up outside map will cause "canvas-drag" event to stick") + * + * @private + * @member resetAllMouseTrackers + * @memberof OpenSeadragon.MouseTracker + */ + $.MouseTracker.resetAllMouseTrackers = function(){ + for(var i = 0; i < MOUSETRACKERS.length; i++){ + if (MOUSETRACKERS[i].isTracking()){ + MOUSETRACKERS[i].setTracking(false); + MOUSETRACKERS[i].setTracking(true); + } + } + }; + + /** + * Provides continuous computation of velocity (speed and direction) of active pointers. + * This is a singleton, used by all MouseTracker instances, as it is unlikely there will ever be more than + * two active gesture pointers at a time. + * + * @private + * @member gesturePointVelocityTracker + * @memberof OpenSeadragon.MouseTracker + */ + $.MouseTracker.gesturePointVelocityTracker = (function () { + var trackerPoints = [], + intervalId = 0, + lastTime = 0; + + // Generates a unique identifier for a tracked gesture point + var _generateGuid = function ( tracker, gPoint ) { + return tracker.hash.toString() + gPoint.type + gPoint.id.toString(); + }; + + // Interval timer callback. Computes velocity for all tracked gesture points. + var _doTracking = function () { + var i, + len = trackerPoints.length, + trackPoint, + gPoint, + now = $.now(), + elapsedTime, + distance, + speed; + + elapsedTime = now - lastTime; + lastTime = now; + + for ( i = 0; i < len; i++ ) { + trackPoint = trackerPoints[ i ]; + gPoint = trackPoint.gPoint; + // Math.atan2 gives us just what we need for a velocity vector, as we can simply + // use cos()/sin() to extract the x/y velocity components. + gPoint.direction = Math.atan2( gPoint.currentPos.y - trackPoint.lastPos.y, gPoint.currentPos.x - trackPoint.lastPos.x ); + // speed = distance / elapsed time + distance = trackPoint.lastPos.distanceTo( gPoint.currentPos ); + trackPoint.lastPos = gPoint.currentPos; + speed = 1000 * distance / ( elapsedTime + 1 ); + // Simple biased average, favors the most recent speed computation. Smooths out erratic gestures a bit. + gPoint.speed = 0.75 * speed + 0.25 * gPoint.speed; + } + }; + + // Public. Add a gesture point to be tracked + var addPoint = function ( tracker, gPoint ) { + var guid = _generateGuid( tracker, gPoint ); + + trackerPoints.push( + { + guid: guid, + gPoint: gPoint, + lastPos: gPoint.currentPos + } ); + + // Only fire up the interval timer when there's gesture pointers to track + if ( trackerPoints.length === 1 ) { + lastTime = $.now(); + intervalId = window.setInterval( _doTracking, 50 ); + } + }; + + // Public. Stop tracking a gesture point + var removePoint = function ( tracker, gPoint ) { + var guid = _generateGuid( tracker, gPoint ), + i, + len = trackerPoints.length; + for ( i = 0; i < len; i++ ) { + if ( trackerPoints[ i ].guid === guid ) { + trackerPoints.splice( i, 1 ); + // Only run the interval timer if theres gesture pointers to track + len--; + if ( len === 0 ) { + window.clearInterval( intervalId ); + } + break; + } + } + }; + + return { + addPoint: addPoint, + removePoint: removePoint + }; + } )(); + + +/////////////////////////////////////////////////////////////////////////////// +// Pointer event model and feature detection +/////////////////////////////////////////////////////////////////////////////// + + $.MouseTracker.captureElement = document; + + /** + * Detect available mouse wheel event name. + */ + $.MouseTracker.wheelEventName = ( $.Browser.vendor == $.BROWSERS.IE && $.Browser.version > 8 ) || + ( 'onwheel' in document.createElement( 'div' ) ) ? 'wheel' : // Modern browsers support 'wheel' + document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least 'mousewheel' + 'DOMMouseScroll'; // Assume old Firefox + + /** + * Detect legacy mouse capture support. + */ + $.MouseTracker.supportsMouseCapture = (function () { + var divElement = document.createElement( 'div' ); + return $.isFunction( divElement.setCapture ) && $.isFunction( divElement.releaseCapture ); + }()); + + /** + * Detect browser pointer device event model(s) and build appropriate list of events to subscribe to. + */ + $.MouseTracker.subscribeEvents = [ "click", "dblclick", "keydown", "keyup", "keypress", "focus", "blur", $.MouseTracker.wheelEventName ]; + + if( $.MouseTracker.wheelEventName == "DOMMouseScroll" ) { + // Older Firefox + $.MouseTracker.subscribeEvents.push( "MozMousePixelScroll" ); + } + + // Note: window.navigator.pointerEnable is deprecated on IE 11 and not part of W3C spec. + if ( window.PointerEvent && ( window.navigator.pointerEnabled || $.Browser.vendor !== $.BROWSERS.IE ) ) { + // IE11 and other W3C Pointer Event implementations (see http://www.w3.org/TR/pointerevents) + $.MouseTracker.havePointerEvents = true; + $.MouseTracker.subscribeEvents.push( "pointerover", "pointerout", "pointerdown", "pointerup", "pointermove", "pointercancel" ); + $.MouseTracker.unprefixedPointerEvents = true; + if( navigator.maxTouchPoints ) { + $.MouseTracker.maxTouchPoints = navigator.maxTouchPoints; + } else { + $.MouseTracker.maxTouchPoints = 0; + } + $.MouseTracker.haveMouseEnter = false; + } else if ( window.MSPointerEvent && window.navigator.msPointerEnabled ) { + // IE10 + $.MouseTracker.havePointerEvents = true; + $.MouseTracker.subscribeEvents.push( "MSPointerOver", "MSPointerOut", "MSPointerDown", "MSPointerUp", "MSPointerMove", "MSPointerCancel" ); + $.MouseTracker.unprefixedPointerEvents = false; + if( navigator.msMaxTouchPoints ) { + $.MouseTracker.maxTouchPoints = navigator.msMaxTouchPoints; + } else { + $.MouseTracker.maxTouchPoints = 0; + } + $.MouseTracker.haveMouseEnter = false; + } else { + // Legacy W3C mouse events + $.MouseTracker.havePointerEvents = false; + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + $.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave" ); + $.MouseTracker.haveMouseEnter = true; + } else { + $.MouseTracker.subscribeEvents.push( "mouseover", "mouseout" ); + $.MouseTracker.haveMouseEnter = false; + } + $.MouseTracker.subscribeEvents.push( "mousedown", "mouseup", "mousemove" ); + if ( 'ontouchstart' in window ) { + // iOS, Android, and other W3c Touch Event implementations + // (see http://www.w3.org/TR/touch-events/) + // (see https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html) + // (see https://developer.apple.com/library/safari/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html) + $.MouseTracker.subscribeEvents.push( "touchstart", "touchend", "touchmove", "touchcancel" ); + } + if ( 'ongesturestart' in window ) { + // iOS (see https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html) + // Subscribe to these to prevent default gesture handling + $.MouseTracker.subscribeEvents.push( "gesturestart", "gesturechange" ); + } + $.MouseTracker.mousePointerId = "legacy-mouse"; + $.MouseTracker.maxTouchPoints = 10; + } + + +/////////////////////////////////////////////////////////////////////////////// +// Classes and typedefs +/////////////////////////////////////////////////////////////////////////////// + + /** + * Represents a point of contact on the screen made by a mouse cursor, pen, touch, or other pointer device. + * + * @typedef {Object} GesturePoint + * @memberof OpenSeadragon.MouseTracker + * + * @property {Number} id + * Identifier unique from all other active GesturePoints for a given pointer device. + * @property {String} type + * The pointer device type: "mouse", "touch", "pen", etc. + * @property {Boolean} captured + * True if events for the gesture point are captured to the tracked element. + * @property {Boolean} isPrimary + * True if the gesture point is a master pointer amongst the set of active pointers for each pointer type. True for mouse and primary (first) touch/pen pointers. + * @property {Boolean} insideElementPressed + * True if button pressed or contact point initiated inside the screen area of the tracked element. + * @property {Boolean} insideElement + * True if pointer or contact point is currently inside the bounds of the tracked element. + * @property {Number} speed + * Current computed speed, in pixels per second. + * @property {Number} direction + * Current computed direction, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0. + * @property {OpenSeadragon.Point} contactPos + * The initial pointer contact position, relative to the page including any scrolling. Only valid if the pointer has contact (pressed, touch contact, pen contact). + * @property {Number} contactTime + * The initial pointer contact time, in milliseconds. Only valid if the pointer has contact (pressed, touch contact, pen contact). + * @property {OpenSeadragon.Point} lastPos + * The last pointer position, relative to the page including any scrolling. + * @property {Number} lastTime + * The last pointer contact time, in milliseconds. + * @property {OpenSeadragon.Point} currentPos + * The current pointer position, relative to the page including any scrolling. + * @property {Number} currentTime + * The current pointer contact time, in milliseconds. + */ + + + /** + * @class GesturePointList + * @classdesc Provides an abstraction for a set of active {@link OpenSeadragon.MouseTracker.GesturePoint|GesturePoint} objects for a given pointer device type. + * Active pointers are any pointer being tracked for this element which are in the hit-test area + * of the element (for hover-capable devices) and/or have contact or a button press initiated in the element. + * @memberof OpenSeadragon.MouseTracker + * @param {String} type - The pointer device type: "mouse", "touch", "pen", etc. + */ + $.MouseTracker.GesturePointList = function ( type ) { + this._gPoints = []; + /** + * The pointer device type: "mouse", "touch", "pen", etc. + * @member {String} type + * @memberof OpenSeadragon.MouseTracker.GesturePointList# + */ + this.type = type; + /** + * Current buttons pressed for the device. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @member {Number} buttons + * @memberof OpenSeadragon.MouseTracker.GesturePointList# + */ + this.buttons = 0; + /** + * Current number of contact points (touch points, mouse down, etc.) for the device. + * @member {Number} contacts + * @memberof OpenSeadragon.MouseTracker.GesturePointList# + */ + this.contacts = 0; + /** + * Current number of clicks for the device. Used for multiple click gesture tracking. + * @member {Number} clicks + * @memberof OpenSeadragon.MouseTracker.GesturePointList# + */ + this.clicks = 0; + /** + * Current number of captured pointers for the device. + * @member {Number} captureCount + * @memberof OpenSeadragon.MouseTracker.GesturePointList# + */ + this.captureCount = 0; + }; + + /** @lends OpenSeadragon.MouseTracker.GesturePointList.prototype */ + $.MouseTracker.GesturePointList.prototype = { + /** + * @function + * @returns {Number} Number of gesture points in the list. + */ + getLength: function () { + return this._gPoints.length; + }, + /** + * @function + * @returns {Array.} The list of gesture points in the list as an array (read-only). + */ + asArray: function () { + return this._gPoints; + }, + /** + * @function + * @param {OpenSeadragon.MouseTracker.GesturePoint} gesturePoint - A gesture point to add to the list. + * @returns {Number} Number of gesture points in the list. + */ + add: function ( gp ) { + return this._gPoints.push( gp ); + }, + /** + * @function + * @param {Number} id - The id of the gesture point to remove from the list. + * @returns {Number} Number of gesture points in the list. + */ + removeById: function ( id ) { + var i, + len = this._gPoints.length; + for ( i = 0; i < len; i++ ) { + if ( this._gPoints[ i ].id === id ) { + this._gPoints.splice( i, 1 ); + break; + } + } + return this._gPoints.length; + }, + /** + * @function + * @param {Number} index - The index of the gesture point to retrieve from the list. + * @returns {OpenSeadragon.MouseTracker.GesturePoint|null} The gesture point at the given index, or null if not found. + */ + getByIndex: function ( index ) { + if ( index < this._gPoints.length) { + return this._gPoints[ index ]; + } + + return null; + }, + /** + * @function + * @param {Number} id - The id of the gesture point to retrieve from the list. + * @returns {OpenSeadragon.MouseTracker.GesturePoint|null} The gesture point with the given id, or null if not found. + */ + getById: function ( id ) { + var i, + len = this._gPoints.length; + for ( i = 0; i < len; i++ ) { + if ( this._gPoints[ i ].id === id ) { + return this._gPoints[ i ]; + } + } + return null; + }, + /** + * @function + * @returns {OpenSeadragon.MouseTracker.GesturePoint|null} The primary gesture point in the list, or null if not found. + */ + getPrimary: function ( id ) { + var i, + len = this._gPoints.length; + for ( i = 0; i < len; i++ ) { + if ( this._gPoints[ i ].isPrimary ) { + return this._gPoints[ i ]; + } + } + return null; + }, + + /** + * Increment this pointer's contact count. + * It will evaluate whether this pointer type is allowed to have multiple contacts. + * @function + */ + addContact: function() { + ++this.contacts; + + if (this.contacts > 1 && (this.type === "mouse" || this.type === "pen")) { + this.contacts = 1; + } + }, + + /** + * Decrement this pointer's contact count. + * It will make sure the count does not go below 0. + * @function + */ + removeContact: function() { + --this.contacts; + + if (this.contacts < 0) { + this.contacts = 0; + } + } + }; + + +/////////////////////////////////////////////////////////////////////////////// +// Utility functions +/////////////////////////////////////////////////////////////////////////////// + + /** + * Removes all tracked pointers. + * @private + * @inner + */ + function clearTrackedPointers( tracker ) { + var delegate = THIS[ tracker.hash ], + i, + pointerListCount = delegate.activePointersLists.length; + + for ( i = 0; i < pointerListCount; i++ ) { + if ( delegate.activePointersLists[ i ].captureCount > 0 ) { + $.removeEvent( + $.MouseTracker.captureElement, + 'mousemove', + delegate.mousemovecaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + 'mouseup', + delegate.mouseupcaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove', + delegate.pointermovecaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp', + delegate.pointerupcaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + 'touchmove', + delegate.touchmovecaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + 'touchend', + delegate.touchendcaptured, + true + ); + + delegate.activePointersLists[ i ].captureCount = 0; + } + } + + for ( i = 0; i < pointerListCount; i++ ) { + delegate.activePointersLists.pop(); + } + } + + /** + * Starts tracking pointer events on the tracked element. + * @private + * @inner + */ + function startTracking( tracker ) { + var delegate = THIS[ tracker.hash ], + event, + i; + + if ( !delegate.tracking ) { + for ( i = 0; i < $.MouseTracker.subscribeEvents.length; i++ ) { + event = $.MouseTracker.subscribeEvents[ i ]; + $.addEvent( + tracker.element, + event, + delegate[ event ], + false + ); + } + + clearTrackedPointers( tracker ); + + delegate.tracking = true; + } + } + + /** + * Stops tracking pointer events on the tracked element. + * @private + * @inner + */ + function stopTracking( tracker ) { + var delegate = THIS[ tracker.hash ], + event, + i; + + if ( delegate.tracking ) { + for ( i = 0; i < $.MouseTracker.subscribeEvents.length; i++ ) { + event = $.MouseTracker.subscribeEvents[ i ]; + $.removeEvent( + tracker.element, + event, + delegate[ event ], + false + ); + } + + clearTrackedPointers( tracker ); + + delegate.tracking = false; + } + } + + /** + * @private + * @inner + */ + function getCaptureEventParams( tracker, pointerType ) { + var delegate = THIS[ tracker.hash ]; + + if ( pointerType === 'pointerevent' ) { + return { + upName: $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp', + upHandler: delegate.pointerupcaptured, + moveName: $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove', + moveHandler: delegate.pointermovecaptured + }; + } else if ( pointerType === 'mouse' ) { + return { + upName: 'mouseup', + upHandler: delegate.mouseupcaptured, + moveName: 'mousemove', + moveHandler: delegate.mousemovecaptured + }; + } else if ( pointerType === 'touch' ) { + return { + upName: 'touchend', + upHandler: delegate.touchendcaptured, + moveName: 'touchmove', + moveHandler: delegate.touchmovecaptured + }; + } else { + throw new Error( "MouseTracker.getCaptureEventParams: Unknown pointer type." ); + } + } + + /** + * Begin capturing pointer events to the tracked element. + * @private + * @inner + */ + function capturePointer( tracker, pointerType, pointerCount ) { + var pointsList = tracker.getActivePointersListByType( pointerType ), + eventParams; + + pointsList.captureCount += (pointerCount || 1); + + if ( pointsList.captureCount === 1 ) { + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + tracker.element.setCapture( true ); + } else { + eventParams = getCaptureEventParams( tracker, $.MouseTracker.havePointerEvents ? 'pointerevent' : pointerType ); + // We emulate mouse capture by hanging listeners on the document object. + // (Note we listen on the capture phase so the captured handlers will get called first) + // eslint-disable-next-line no-use-before-define + if (isInIframe && canAccessEvents(window.top)) { + $.addEvent( + window.top, + eventParams.upName, + eventParams.upHandler, + true + ); + } + $.addEvent( + $.MouseTracker.captureElement, + eventParams.upName, + eventParams.upHandler, + true + ); + $.addEvent( + $.MouseTracker.captureElement, + eventParams.moveName, + eventParams.moveHandler, + true + ); + } + } + } + + + /** + * Stop capturing pointer events to the tracked element. + * @private + * @inner + */ + function releasePointer( tracker, pointerType, pointerCount ) { + var pointsList = tracker.getActivePointersListByType( pointerType ), + eventParams; + + pointsList.captureCount -= (pointerCount || 1); + + if ( pointsList.captureCount === 0 ) { + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + tracker.element.releaseCapture(); + } else { + eventParams = getCaptureEventParams( tracker, $.MouseTracker.havePointerEvents ? 'pointerevent' : pointerType ); + // We emulate mouse capture by hanging listeners on the document object. + // (Note we listen on the capture phase so the captured handlers will get called first) + // eslint-disable-next-line no-use-before-define + if (isInIframe && canAccessEvents(window.top)) { + $.removeEvent( + window.top, + eventParams.upName, + eventParams.upHandler, + true + ); + } + $.removeEvent( + $.MouseTracker.captureElement, + eventParams.moveName, + eventParams.moveHandler, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + eventParams.upName, + eventParams.upHandler, + true + ); + } + } + } + + + /** + * Gets a W3C Pointer Events model compatible pointer type string from a DOM pointer event. + * IE10 used a long integer value, but the W3C specification (and IE11+) use a string "mouse", "touch", "pen", etc. + * @private + * @inner + */ + function getPointerType( event ) { + var pointerTypeStr; + if ( $.MouseTracker.unprefixedPointerEvents ) { + pointerTypeStr = event.pointerType; + } else { + // IE10 + // MSPOINTER_TYPE_TOUCH: 0x00000002 + // MSPOINTER_TYPE_PEN: 0x00000003 + // MSPOINTER_TYPE_MOUSE: 0x00000004 + switch( event.pointerType ) + { + case 0x00000002: + pointerTypeStr = 'touch'; + break; + case 0x00000003: + pointerTypeStr = 'pen'; + break; + case 0x00000004: + pointerTypeStr = 'mouse'; + break; + default: + pointerTypeStr = ''; + } + } + return pointerTypeStr; + } + + + /** + * @private + * @inner + */ + function getMouseAbsolute( event ) { + return $.getMousePosition( event ); + } + + /** + * @private + * @inner + */ + function getMouseRelative( event, element ) { + return getPointRelativeToAbsolute( getMouseAbsolute( event ), element ); + } + + /** + * @private + * @inner + */ + function getPointRelativeToAbsolute( point, element ) { + var offset = $.getElementOffset( element ); + return point.minus( offset ); + } + + /** + * @private + * @inner + */ + function getCenterPoint( point1, point2 ) { + return new $.Point( ( point1.x + point2.x ) / 2, ( point1.y + point2.y ) / 2 ); + } + + +/////////////////////////////////////////////////////////////////////////////// +// Device-specific DOM event handlers +/////////////////////////////////////////////////////////////////////////////// + + /** + * @private + * @inner + */ + function onClick( tracker, event ) { + if ( tracker.clickHandler ) { + $.cancelEvent( event ); + } + } + + + /** + * @private + * @inner + */ + function onDblClick( tracker, event ) { + if ( tracker.dblClickHandler ) { + $.cancelEvent( event ); + } + } + + + /** + * @private + * @inner + */ + function onKeyDown( tracker, event ) { + //$.console.log( "keydown %s %s %s %s %s", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey ); + var propagate; + if ( tracker.keyDownHandler ) { + event = $.getEvent( event ); + propagate = tracker.keyDownHandler( + { + eventSource: tracker, + keyCode: event.keyCode ? event.keyCode : event.charCode, + ctrl: event.ctrlKey, + shift: event.shiftKey, + alt: event.altKey, + meta: event.metaKey, + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( !propagate ) { + $.cancelEvent( event ); + } + } + } + + + /** + * @private + * @inner + */ + function onKeyUp( tracker, event ) { + //$.console.log( "keyup %s %s %s %s %s", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey ); + var propagate; + if ( tracker.keyUpHandler ) { + event = $.getEvent( event ); + propagate = tracker.keyUpHandler( + { + eventSource: tracker, + keyCode: event.keyCode ? event.keyCode : event.charCode, + ctrl: event.ctrlKey, + shift: event.shiftKey, + alt: event.altKey, + meta: event.metaKey, + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( !propagate ) { + $.cancelEvent( event ); + } + } + } + + + /** + * @private + * @inner + */ + function onKeyPress( tracker, event ) { + //$.console.log( "keypress %s %s %s %s %s", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey ); + var propagate; + if ( tracker.keyHandler ) { + event = $.getEvent( event ); + propagate = tracker.keyHandler( + { + eventSource: tracker, + keyCode: event.keyCode ? event.keyCode : event.charCode, + ctrl: event.ctrlKey, + shift: event.shiftKey, + alt: event.altKey, + meta: event.metaKey, + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( !propagate ) { + $.cancelEvent( event ); + } + } + } + + + /** + * @private + * @inner + */ + function onFocus( tracker, event ) { + //console.log( "focus %s", event ); + var propagate; + if ( tracker.focusHandler ) { + event = $.getEvent( event ); + propagate = tracker.focusHandler( + { + eventSource: tracker, + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } + + + /** + * @private + * @inner + */ + function onBlur( tracker, event ) { + //console.log( "blur %s", event ); + var propagate; + if ( tracker.blurHandler ) { + event = $.getEvent( event ); + propagate = tracker.blurHandler( + { + eventSource: tracker, + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } + + + /** + * Handler for 'wheel' events + * + * @private + * @inner + */ + function onWheel( tracker, event ) { + handleWheelEvent( tracker, event, event ); + } + + + /** + * Handler for 'mousewheel', 'DOMMouseScroll', and 'MozMousePixelScroll' events + * + * @private + * @inner + */ + function onMouseWheel( tracker, event ) { + event = $.getEvent( event ); + + // Simulate a 'wheel' event + var simulatedEvent = { + target: event.target || event.srcElement, + type: "wheel", + shiftKey: event.shiftKey || false, + clientX: event.clientX, + clientY: event.clientY, + pageX: event.pageX ? event.pageX : event.clientX, + pageY: event.pageY ? event.pageY : event.clientY, + deltaMode: event.type == "MozMousePixelScroll" ? 0 : 1, // 0=pixel, 1=line, 2=page + deltaX: 0, + deltaZ: 0 + }; + + // Calculate deltaY + if ( $.MouseTracker.wheelEventName == "mousewheel" ) { + simulatedEvent.deltaY = -event.wheelDelta / $.DEFAULT_SETTINGS.pixelsPerWheelLine; + } else { + simulatedEvent.deltaY = event.detail; + } + + handleWheelEvent( tracker, simulatedEvent, event ); + } + + + /** + * Handles 'wheel' events. + * The event may be simulated by the legacy mouse wheel event handler (onMouseWheel()). + * + * @private + * @inner + */ + function handleWheelEvent( tracker, event, originalEvent ) { + var nDelta = 0, + propagate; + + // The nDelta variable is gated to provide smooth z-index scrolling + // since the mouse wheel allows for substantial deltas meant for rapid + // y-index scrolling. + // event.deltaMode: 0=pixel, 1=line, 2=page + // TODO: Deltas in pixel mode should be accumulated then a scroll value computed after $.DEFAULT_SETTINGS.pixelsPerWheelLine threshold reached + nDelta = event.deltaY < 0 ? 1 : -1; + + if ( tracker.scrollHandler ) { + propagate = tracker.scrollHandler( + { + eventSource: tracker, + pointerType: 'mouse', + position: getMouseRelative( event, tracker.element ), + scroll: nDelta, + shift: event.shiftKey, + isTouchEvent: false, + originalEvent: originalEvent, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( originalEvent ); + } + } + } + + + /** + * @private + * @inner + */ + function isParentChild( parent, child ) + { + if ( parent === child ) { + return false; + } + while ( child && child !== parent ) { + child = child.parentNode; + } + return child === parent; + } + + + /** + * Only used on IE 8 + * + * @private + * @inner + */ + function onMouseEnter( tracker, event ) { + event = $.getEvent( event ); + + handleMouseEnter( tracker, event ); + } + + + /** + * @private + * @inner + */ + function onMouseOver( tracker, event ) { + event = $.getEvent( event ); + + if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { + return; + } + + handleMouseEnter( tracker, event ); + } + + + /** + * @private + * @inner + */ + function handleMouseEnter( tracker, event ) { + var gPoint = { + id: $.MouseTracker.mousePointerId, + type: 'mouse', + isPrimary: true, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + updatePointersEnter( tracker, event, [ gPoint ] ); + } + + + /** + * Only used on IE 8 + * + * @private + * @inner + */ + function onMouseLeave( tracker, event ) { + event = $.getEvent( event ); + + handleMouseExit( tracker, event ); + } + + + /** + * @private + * @inner + */ + function onMouseOut( tracker, event ) { + event = $.getEvent( event ); + + if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { + return; + } + + handleMouseExit( tracker, event ); + } + + + /** + * @private + * @inner + */ + function handleMouseExit( tracker, event ) { + var gPoint = { + id: $.MouseTracker.mousePointerId, + type: 'mouse', + isPrimary: true, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + updatePointersExit( tracker, event, [ gPoint ] ); + } + + + /** + * Returns a W3C DOM level 3 standard button value given an event.button property: + * -1 == none, 0 == primary/left, 1 == middle, 2 == secondary/right, 3 == X1/back, 4 == X2/forward, 5 == eraser (pen) + * @private + * @inner + */ + function getStandardizedButton( button ) { + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + // On IE 8, 0 == none, 1 == left, 2 == right, 3 == left and right, 4 == middle, 5 == left and middle, 6 == right and middle, 7 == all three + // TODO: Support chorded (multiple) button presses on IE 8? + if ( button === 1 ) { + return 0; + } else if ( button === 2 ) { + return 2; + } else if ( button === 4 ) { + return 1; + } else { + return -1; + } + } else { + return button; + } + } + + + /** + * @private + * @inner + */ + function onMouseDown( tracker, event ) { + var gPoint; + + event = $.getEvent( event ); + + gPoint = { + id: $.MouseTracker.mousePointerId, + type: 'mouse', + isPrimary: true, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + if ( updatePointersDown( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) { + $.stopEvent( event ); + capturePointer( tracker, 'mouse' ); + } + + if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler ) { + $.cancelEvent( event ); + } + } + + + /** + * @private + * @inner + */ + function onMouseUp( tracker, event ) { + handleMouseUp( tracker, event ); + } + + /** + * This handler is attached to the window object (on the capture phase) to emulate mouse capture. + * onMouseUp is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onMouseUpCaptured( tracker, event ) { + handleMouseUp( tracker, event ); + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handleMouseUp( tracker, event ) { + var gPoint; + + event = $.getEvent( event ); + + gPoint = { + id: $.MouseTracker.mousePointerId, + type: 'mouse', + isPrimary: true, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + if ( updatePointersUp( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) { + releasePointer( tracker, 'mouse' ); + } + } + + + /** + * @private + * @inner + */ + function onMouseMove( tracker, event ) { + handleMouseMove( tracker, event ); + } + + + /** + * This handler is attached to the window object (on the capture phase) to emulate mouse capture. + * onMouseMove is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onMouseMoveCaptured( tracker, event ) { + handleMouseMove( tracker, event ); + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handleMouseMove( tracker, event ) { + var gPoint; + + event = $.getEvent( event ); + + gPoint = { + id: $.MouseTracker.mousePointerId, + type: 'mouse', + isPrimary: true, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + updatePointersMove( tracker, event, [ gPoint ] ); + } + + + /** + * @private + * @inner + */ + function abortContacts( tracker, event, pointsList ) { + var i, + gPointCount = pointsList.getLength(), + abortGPoints = []; + + // Check contact count for hoverable pointer types before aborting + if (pointsList.type === 'touch' || pointsList.contacts > 0) { + for ( i = 0; i < gPointCount; i++ ) { + abortGPoints.push( pointsList.getByIndex( i ) ); + } + + if ( abortGPoints.length > 0 ) { + // simulate touchend/mouseup + updatePointersUp( tracker, event, abortGPoints, 0 ); // 0 means primary button press/release or touch contact + // release pointer capture + pointsList.captureCount = 1; + releasePointer( tracker, pointsList.type ); + // simulate touchleave/mouseout + updatePointersExit( tracker, event, abortGPoints ); + } + } + } + + + /** + * @private + * @inner + */ + function onTouchStart( tracker, event ) { + var time, + i, + j, + touchCount = event.changedTouches.length, + gPoints = [], + parentGPoints, + pointsList = tracker.getActivePointersListByType( 'touch' ); + + time = $.now(); + + if ( pointsList.getLength() > event.touches.length - touchCount ) { + $.console.warn('Tracked touch contact count doesn\'t match event.touches.length. Removing all tracked touch pointers.'); + abortContacts( tracker, event, pointsList ); + } + + for ( i = 0; i < touchCount; i++ ) { + gPoints.push( { + id: event.changedTouches[ i ].identifier, + type: 'touch', + // isPrimary not set - let the updatePointers functions determine it + currentPos: getMouseAbsolute( event.changedTouches[ i ] ), + currentTime: time + } ); + } + + // simulate touchenter on our tracked element + updatePointersEnter( tracker, event, gPoints ); + + // simulate touchenter on our tracked element's tracked ancestor elements + for ( i = 0; i < MOUSETRACKERS.length; i++ ) { + if ( MOUSETRACKERS[ i ] !== tracker && MOUSETRACKERS[ i ].isTracking() && isParentChild( MOUSETRACKERS[ i ].element, tracker.element ) ) { + parentGPoints = []; + for ( j = 0; j < touchCount; j++ ) { + parentGPoints.push( { + id: event.changedTouches[ j ].identifier, + type: 'touch', + // isPrimary not set - let the updatePointers functions determine it + currentPos: getMouseAbsolute( event.changedTouches[ j ] ), + currentTime: time + } ); + } + updatePointersEnter( MOUSETRACKERS[ i ], event, parentGPoints ); + } + } + + if ( updatePointersDown( tracker, event, gPoints, 0 ) ) { // 0 means primary button press/release or touch contact + $.stopEvent( event ); + capturePointer( tracker, 'touch', touchCount ); + } + + $.cancelEvent( event ); + } + + + /** + * @private + * @inner + */ + function onTouchEnd( tracker, event ) { + handleTouchEnd( tracker, event ); + } + + + /** + * This handler is attached to the window object (on the capture phase) to emulate pointer capture. + * onTouchEnd is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onTouchEndCaptured( tracker, event ) { + handleTouchEnd( tracker, event ); + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handleTouchEnd( tracker, event ) { + var time, + i, + j, + touchCount = event.changedTouches.length, + gPoints = [], + parentGPoints; + + time = $.now(); + + for ( i = 0; i < touchCount; i++ ) { + gPoints.push( { + id: event.changedTouches[ i ].identifier, + type: 'touch', + // isPrimary not set - let the updatePointers functions determine it + currentPos: getMouseAbsolute( event.changedTouches[ i ] ), + currentTime: time + } ); + } + + if ( updatePointersUp( tracker, event, gPoints, 0 ) ) { + releasePointer( tracker, 'touch', touchCount ); + } + + // simulate touchleave on our tracked element + updatePointersExit( tracker, event, gPoints ); + + // simulate touchleave on our tracked element's tracked ancestor elements + for ( i = 0; i < MOUSETRACKERS.length; i++ ) { + if ( MOUSETRACKERS[ i ] !== tracker && MOUSETRACKERS[ i ].isTracking() && isParentChild( MOUSETRACKERS[ i ].element, tracker.element ) ) { + parentGPoints = []; + for ( j = 0; j < touchCount; j++ ) { + parentGPoints.push( { + id: event.changedTouches[ j ].identifier, + type: 'touch', + // isPrimary not set - let the updatePointers functions determine it + currentPos: getMouseAbsolute( event.changedTouches[ j ] ), + currentTime: time + } ); + } + updatePointersExit( MOUSETRACKERS[ i ], event, parentGPoints ); + } + } + + $.cancelEvent( event ); + } + + + /** + * @private + * @inner + */ + function onTouchMove( tracker, event ) { + handleTouchMove( tracker, event ); + } + + + /** + * This handler is attached to the window object (on the capture phase) to emulate pointer capture. + * onTouchMove is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onTouchMoveCaptured( tracker, event ) { + handleTouchMove( tracker, event ); + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handleTouchMove( tracker, event ) { + var i, + touchCount = event.changedTouches.length, + gPoints = []; + + for ( i = 0; i < touchCount; i++ ) { + gPoints.push( { + id: event.changedTouches[ i ].identifier, + type: 'touch', + // isPrimary not set - let the updatePointers functions determine it + currentPos: getMouseAbsolute( event.changedTouches[ i ] ), + currentTime: $.now() + } ); + } + + updatePointersMove( tracker, event, gPoints ); + + $.cancelEvent( event ); + } + + + /** + * @private + * @inner + */ + function onTouchCancel( tracker, event ) { + var pointsList = tracker.getActivePointersListByType('touch'); + + abortContacts( tracker, event, pointsList ); + } + + + /** + * @private + * @inner + */ + function onGestureStart( tracker, event ) { + event.stopPropagation(); + event.preventDefault(); + return false; + } + + + /** + * @private + * @inner + */ + function onGestureChange( tracker, event ) { + event.stopPropagation(); + event.preventDefault(); + return false; + } + + + /** + * @private + * @inner + */ + function onPointerOver( tracker, event ) { + var gPoint; + + if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { + return; + } + + gPoint = { + id: event.pointerId, + type: getPointerType( event ), + isPrimary: event.isPrimary, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + updatePointersEnter( tracker, event, [ gPoint ] ); + } + + + /** + * @private + * @inner + */ + function onPointerOut( tracker, event ) { + var gPoint; + + if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { + return; + } + + gPoint = { + id: event.pointerId, + type: getPointerType( event ), + isPrimary: event.isPrimary, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + updatePointersExit( tracker, event, [ gPoint ] ); + } + + + /** + * @private + * @inner + */ + function onPointerDown( tracker, event ) { + var gPoint; + + gPoint = { + id: event.pointerId, + type: getPointerType( event ), + isPrimary: event.isPrimary, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) { + $.stopEvent( event ); + capturePointer( tracker, gPoint.type ); + } + + if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { + $.cancelEvent( event ); + } + } + + + /** + * @private + * @inner + */ + function onPointerUp( tracker, event ) { + handlePointerUp( tracker, event ); + } + + + /** + * This handler is attached to the window object (on the capture phase) to emulate mouse capture. + * onPointerUp is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onPointerUpCaptured( tracker, event ) { + var pointsList = tracker.getActivePointersListByType( getPointerType( event ) ); + if ( pointsList.getById( event.pointerId ) ) { + handlePointerUp( tracker, event ); + } + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handlePointerUp( tracker, event ) { + var gPoint; + + gPoint = { + id: event.pointerId, + type: getPointerType( event ), + isPrimary: event.isPrimary, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) { + releasePointer( tracker, gPoint.type ); + } + } + + + /** + * @private + * @inner + */ + function onPointerMove( tracker, event ) { + handlePointerMove( tracker, event ); + } + + + /** + * This handler is attached to the window object (on the capture phase) to emulate mouse capture. + * onPointerMove is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onPointerMoveCaptured( tracker, event ) { + var pointsList = tracker.getActivePointersListByType( getPointerType( event ) ); + if ( pointsList.getById( event.pointerId ) ) { + handlePointerMove( tracker, event ); + } + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handlePointerMove( tracker, event ) { + // Pointer changed coordinates, button state, pressure, tilt, or contact geometry (e.g. width and height) + var gPoint; + + gPoint = { + id: event.pointerId, + type: getPointerType( event ), + isPrimary: event.isPrimary, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + updatePointersMove( tracker, event, [ gPoint ] ); + } + + + /** + * @private + * @inner + */ + function onPointerCancel( tracker, event ) { + var gPoint; + + gPoint = { + id: event.pointerId, + type: getPointerType( event ) + }; + + updatePointersCancel( tracker, event, [ gPoint ] ); + } + + +/////////////////////////////////////////////////////////////////////////////// +// Device-agnostic DOM event handlers +/////////////////////////////////////////////////////////////////////////////// + + /** + * @function + * @private + * @inner + * @param {OpenSeadragon.MouseTracker.GesturePointList} pointsList + * The GesturePointList to track the pointer in. + * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint + * Gesture point to track. + * @returns {Number} Number of gesture points in pointsList. + */ + function startTrackingPointer( pointsList, gPoint ) { + + // If isPrimary is not known for the pointer then set it according to our rules: + // true if the first pointer in the gesture, otherwise false + if ( !gPoint.hasOwnProperty( 'isPrimary' ) ) { + if ( pointsList.getLength() === 0 ) { + gPoint.isPrimary = true; + } else { + gPoint.isPrimary = false; + } + } + gPoint.speed = 0; + gPoint.direction = 0; + gPoint.contactPos = gPoint.currentPos; + gPoint.contactTime = gPoint.currentTime; + gPoint.lastPos = gPoint.currentPos; + gPoint.lastTime = gPoint.currentTime; + + return pointsList.add( gPoint ); + } + + + /** + * @function + * @private + * @inner + * @param {OpenSeadragon.MouseTracker.GesturePointList} pointsList + * The GesturePointList to stop tracking the pointer on. + * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint + * Gesture point to stop tracking. + * @returns {Number} Number of gesture points in pointsList. + */ + function stopTrackingPointer( pointsList, gPoint ) { + var listLength, + primaryPoint; + + if ( pointsList.getById( gPoint.id ) ) { + listLength = pointsList.removeById( gPoint.id ); + + // If isPrimary is not known for the pointer and we just removed the primary pointer from the list then we need to set another pointer as primary + if ( !gPoint.hasOwnProperty( 'isPrimary' ) ) { + primaryPoint = pointsList.getPrimary(); + if ( !primaryPoint ) { + primaryPoint = pointsList.getByIndex( 0 ); + if ( primaryPoint ) { + primaryPoint.isPrimary = true; + } + } + } + } else { + listLength = pointsList.getLength(); + } + + return listLength; + } + + + /** + * @function + * @private + * @inner + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the MouseTracker instance. + * @param {Object} event + * A reference to the originating DOM event. + * @param {Array.} gPoints + * Gesture points associated with the event. + */ + function updatePointersEnter( tracker, event, gPoints ) { + var pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ), + i, + gPointCount = gPoints.length, + curGPoint, + updateGPoint, + propagate; + + for ( i = 0; i < gPointCount; i++ ) { + curGPoint = gPoints[ i ]; + updateGPoint = pointsList.getById( curGPoint.id ); + + if ( updateGPoint ) { + // Already tracking the pointer...update it + updateGPoint.insideElement = true; + updateGPoint.lastPos = updateGPoint.currentPos; + updateGPoint.lastTime = updateGPoint.currentTime; + updateGPoint.currentPos = curGPoint.currentPos; + updateGPoint.currentTime = curGPoint.currentTime; + + curGPoint = updateGPoint; + } else { + // Initialize for tracking and add to the tracking list + curGPoint.captured = false; + curGPoint.insideElementPressed = false; + curGPoint.insideElement = true; + startTrackingPointer( pointsList, curGPoint ); + } + + // Enter + if ( tracker.enterHandler ) { + propagate = tracker.enterHandler( + { + eventSource: tracker, + pointerType: curGPoint.type, + position: getPointRelativeToAbsolute( curGPoint.currentPos, tracker.element ), + buttons: pointsList.buttons, + pointers: tracker.getActivePointerCount(), + insideElementPressed: curGPoint.insideElementPressed, + buttonDownAny: pointsList.buttons !== 0, + isTouchEvent: curGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } + } + + + /** + * @function + * @private + * @inner + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the MouseTracker instance. + * @param {Object} event + * A reference to the originating DOM event. + * @param {Array.} gPoints + * Gesture points associated with the event. + */ + function updatePointersExit( tracker, event, gPoints ) { + var pointsList = tracker.getActivePointersListByType(gPoints[0].type), + i, + gPointCount = gPoints.length, + curGPoint, + updateGPoint, + propagate; + + for ( i = 0; i < gPointCount; i++ ) { + curGPoint = gPoints[ i ]; + updateGPoint = pointsList.getById( curGPoint.id ); + + if ( updateGPoint ) { + // Already tracking the pointer. If captured then update it, else stop tracking it + if ( updateGPoint.captured ) { + updateGPoint.insideElement = false; + updateGPoint.lastPos = updateGPoint.currentPos; + updateGPoint.lastTime = updateGPoint.currentTime; + updateGPoint.currentPos = curGPoint.currentPos; + updateGPoint.currentTime = curGPoint.currentTime; + } else { + stopTrackingPointer( pointsList, updateGPoint ); + } + + curGPoint = updateGPoint; + } + + // Exit + if ( tracker.exitHandler ) { + propagate = tracker.exitHandler( + { + eventSource: tracker, + pointerType: curGPoint.type, + position: getPointRelativeToAbsolute( curGPoint.currentPos, tracker.element ), + buttons: pointsList.buttons, + pointers: tracker.getActivePointerCount(), + insideElementPressed: updateGPoint ? updateGPoint.insideElementPressed : false, + buttonDownAny: pointsList.buttons !== 0, + isTouchEvent: curGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } + } + + + /** + * @function + * @private + * @inner + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the MouseTracker instance. + * @param {Object} event + * A reference to the originating DOM event. + * @param {Array.} gPoints + * Gesture points associated with the event. + * @param {Number} buttonChanged + * The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. + * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model, + * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events. + * + * @returns {Boolean} True if pointers should be captured to the tracked element, otherwise false. + */ + function updatePointersDown( tracker, event, gPoints, buttonChanged ) { + var delegate = THIS[ tracker.hash ], + propagate, + pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ), + i, + gPointCount = gPoints.length, + curGPoint, + updateGPoint; + + if ( typeof event.buttons !== 'undefined' ) { + pointsList.buttons = event.buttons; + } else { + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + if ( buttonChanged === 0 ) { + // Primary + pointsList.buttons += 1; + } else if ( buttonChanged === 1 ) { + // Aux + pointsList.buttons += 4; + } else if ( buttonChanged === 2 ) { + // Secondary + pointsList.buttons += 2; + } else if ( buttonChanged === 3 ) { + // X1 (Back) + pointsList.buttons += 8; + } else if ( buttonChanged === 4 ) { + // X2 (Forward) + pointsList.buttons += 16; + } else if ( buttonChanged === 5 ) { + // Pen Eraser + pointsList.buttons += 32; + } + } else { + if ( buttonChanged === 0 ) { + // Primary + pointsList.buttons |= 1; + } else if ( buttonChanged === 1 ) { + // Aux + pointsList.buttons |= 4; + } else if ( buttonChanged === 2 ) { + // Secondary + pointsList.buttons |= 2; + } else if ( buttonChanged === 3 ) { + // X1 (Back) + pointsList.buttons |= 8; + } else if ( buttonChanged === 4 ) { + // X2 (Forward) + pointsList.buttons |= 16; + } else if ( buttonChanged === 5 ) { + // Pen Eraser + pointsList.buttons |= 32; + } + } + } + + // Some pointers may steal control from another pointer without firing the appropriate release events + // e.g. Touching a screen while click-dragging with certain mice. + var otherPointsLists = tracker.getActivePointersListsExceptType(gPoints[ 0 ].type); + for (i = 0; i < otherPointsLists.length; i++) { + //If another pointer has contact, simulate the release + abortContacts(tracker, event, otherPointsLists[i]); // No-op if no active pointer + } + + // Only capture and track primary button, pen, and touch contacts + if ( buttonChanged !== 0 ) { + // Aux Press + if ( tracker.nonPrimaryPressHandler ) { + propagate = tracker.nonPrimaryPressHandler( + { + eventSource: tracker, + pointerType: gPoints[ 0 ].type, + position: getPointRelativeToAbsolute( gPoints[ 0 ].currentPos, tracker.element ), + button: buttonChanged, + buttons: pointsList.buttons, + isTouchEvent: gPoints[ 0 ].type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + + return false; + } + + for ( i = 0; i < gPointCount; i++ ) { + curGPoint = gPoints[ i ]; + updateGPoint = pointsList.getById( curGPoint.id ); + + if ( updateGPoint ) { + // Already tracking the pointer...update it + updateGPoint.captured = true; + updateGPoint.insideElementPressed = true; + updateGPoint.insideElement = true; + updateGPoint.contactPos = curGPoint.currentPos; + updateGPoint.contactTime = curGPoint.currentTime; + updateGPoint.lastPos = updateGPoint.currentPos; + updateGPoint.lastTime = updateGPoint.currentTime; + updateGPoint.currentPos = curGPoint.currentPos; + updateGPoint.currentTime = curGPoint.currentTime; + + curGPoint = updateGPoint; + } else { + // Initialize for tracking and add to the tracking list (no pointerover or pointermove event occurred before this) + curGPoint.captured = true; + curGPoint.insideElementPressed = true; + curGPoint.insideElement = true; + startTrackingPointer( pointsList, curGPoint ); + } + + pointsList.addContact(); + //$.console.log('contacts++ ', pointsList.contacts); + + if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { + $.MouseTracker.gesturePointVelocityTracker.addPoint( tracker, curGPoint ); + } + + if ( pointsList.contacts === 1 ) { + // Press + if ( tracker.pressHandler ) { + propagate = tracker.pressHandler( + { + eventSource: tracker, + pointerType: curGPoint.type, + position: getPointRelativeToAbsolute( curGPoint.contactPos, tracker.element ), + buttons: pointsList.buttons, + isTouchEvent: curGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } else if ( pointsList.contacts === 2 ) { + if ( tracker.pinchHandler && curGPoint.type === 'touch' ) { + // Initialize for pinch + delegate.pinchGPoints = pointsList.asArray(); + delegate.lastPinchDist = delegate.currentPinchDist = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos ); + delegate.lastPinchCenter = delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos ); + } + } + } + + return true; + } + + + /** + * @function + * @private + * @inner + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the MouseTracker instance. + * @param {Object} event + * A reference to the originating DOM event. + * @param {Array.} gPoints + * Gesture points associated with the event. + * @param {Number} buttonChanged + * The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. + * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model, + * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events. + * + * @returns {Boolean} True if pointer capture should be released from the tracked element, otherwise false. + */ + function updatePointersUp( tracker, event, gPoints, buttonChanged ) { + var delegate = THIS[ tracker.hash ], + pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ), + propagate, + releasePoint, + releaseTime, + i, + gPointCount = gPoints.length, + curGPoint, + updateGPoint, + releaseCapture = false, + wasCaptured = false, + quick; + + if ( typeof event.buttons !== 'undefined' ) { + pointsList.buttons = event.buttons; + } else { + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + if ( buttonChanged === 0 ) { + // Primary + pointsList.buttons -= 1; + } else if ( buttonChanged === 1 ) { + // Aux + pointsList.buttons -= 4; + } else if ( buttonChanged === 2 ) { + // Secondary + pointsList.buttons -= 2; + } else if ( buttonChanged === 3 ) { + // X1 (Back) + pointsList.buttons -= 8; + } else if ( buttonChanged === 4 ) { + // X2 (Forward) + pointsList.buttons -= 16; + } else if ( buttonChanged === 5 ) { + // Pen Eraser + pointsList.buttons -= 32; + } + } else { + if ( buttonChanged === 0 ) { + // Primary + pointsList.buttons ^= ~1; + } else if ( buttonChanged === 1 ) { + // Aux + pointsList.buttons ^= ~4; + } else if ( buttonChanged === 2 ) { + // Secondary + pointsList.buttons ^= ~2; + } else if ( buttonChanged === 3 ) { + // X1 (Back) + pointsList.buttons ^= ~8; + } else if ( buttonChanged === 4 ) { + // X2 (Forward) + pointsList.buttons ^= ~16; + } else if ( buttonChanged === 5 ) { + // Pen Eraser + pointsList.buttons ^= ~32; + } + } + } + + // Only capture and track primary button, pen, and touch contacts + if ( buttonChanged !== 0 ) { + // Aux Release + if ( tracker.nonPrimaryReleaseHandler ) { + propagate = tracker.nonPrimaryReleaseHandler( + { + eventSource: tracker, + pointerType: gPoints[ 0 ].type, + position: getPointRelativeToAbsolute(gPoints[0].currentPos, tracker.element), + button: buttonChanged, + buttons: pointsList.buttons, + isTouchEvent: gPoints[ 0 ].type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + + // A primary mouse button may have been released while the non-primary button was down + var otherPointsList = tracker.getActivePointersListByType("mouse"); + // Stop tracking the mouse; see https://github.com/openseadragon/openseadragon/pull/1223 + abortContacts(tracker, event, otherPointsList); // No-op if no active pointer + + return false; + } + + for ( i = 0; i < gPointCount; i++ ) { + curGPoint = gPoints[ i ]; + updateGPoint = pointsList.getById( curGPoint.id ); + + if ( updateGPoint ) { + // Update the pointer, stop tracking it if not still in this element + if ( updateGPoint.captured ) { + updateGPoint.captured = false; + releaseCapture = true; + wasCaptured = true; + } + updateGPoint.lastPos = updateGPoint.currentPos; + updateGPoint.lastTime = updateGPoint.currentTime; + updateGPoint.currentPos = curGPoint.currentPos; + updateGPoint.currentTime = curGPoint.currentTime; + if ( !updateGPoint.insideElement ) { + stopTrackingPointer( pointsList, updateGPoint ); + } + + releasePoint = updateGPoint.currentPos; + releaseTime = updateGPoint.currentTime; + + if ( wasCaptured ) { + // Pointer was activated in our element but could have been removed in any element since events are captured to our element + + pointsList.removeContact(); + //$.console.log('contacts-- ', pointsList.contacts); + + if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { + $.MouseTracker.gesturePointVelocityTracker.removePoint( tracker, updateGPoint ); + } + + if ( pointsList.contacts === 0 ) { + + // Release (pressed in our element) + if ( tracker.releaseHandler ) { + propagate = tracker.releaseHandler( + { + eventSource: tracker, + pointerType: updateGPoint.type, + position: getPointRelativeToAbsolute( releasePoint, tracker.element ), + buttons: pointsList.buttons, + insideElementPressed: updateGPoint.insideElementPressed, + insideElementReleased: updateGPoint.insideElement, + isTouchEvent: updateGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + + // Drag End + if ( tracker.dragEndHandler && !updateGPoint.currentPos.equals( updateGPoint.contactPos ) ) { + propagate = tracker.dragEndHandler( + { + eventSource: tracker, + pointerType: updateGPoint.type, + position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ), + speed: updateGPoint.speed, + direction: updateGPoint.direction, + shift: event.shiftKey, + isTouchEvent: updateGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + + // Click / Double-Click + if ( ( tracker.clickHandler || tracker.dblClickHandler ) && updateGPoint.insideElement ) { + quick = releaseTime - updateGPoint.contactTime <= tracker.clickTimeThreshold && + updateGPoint.contactPos.distanceTo( releasePoint ) <= tracker.clickDistThreshold; + + // Click + if ( tracker.clickHandler ) { + propagate = tracker.clickHandler( + { + eventSource: tracker, + pointerType: updateGPoint.type, + position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ), + quick: quick, + shift: event.shiftKey, + isTouchEvent: updateGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + + // Double-Click + if ( tracker.dblClickHandler && quick ) { + pointsList.clicks++; + if ( pointsList.clicks === 1 ) { + delegate.lastClickPos = releasePoint; + /*jshint loopfunc:true*/ + delegate.dblClickTimeOut = setTimeout( function() { + pointsList.clicks = 0; + }, tracker.dblClickTimeThreshold ); + /*jshint loopfunc:false*/ + } else if ( pointsList.clicks === 2 ) { + clearTimeout( delegate.dblClickTimeOut ); + pointsList.clicks = 0; + if ( delegate.lastClickPos.distanceTo( releasePoint ) <= tracker.dblClickDistThreshold ) { + propagate = tracker.dblClickHandler( + { + eventSource: tracker, + pointerType: updateGPoint.type, + position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ), + shift: event.shiftKey, + isTouchEvent: updateGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + delegate.lastClickPos = null; + } + } + } + } else if ( pointsList.contacts === 2 ) { + if ( tracker.pinchHandler && updateGPoint.type === 'touch' ) { + // Reset for pinch + delegate.pinchGPoints = pointsList.asArray(); + delegate.lastPinchDist = delegate.currentPinchDist = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos ); + delegate.lastPinchCenter = delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos ); + } + } + } else { + // Pointer was activated in another element but removed in our element + + // Release (pressed in another element) + if ( tracker.releaseHandler ) { + propagate = tracker.releaseHandler( + { + eventSource: tracker, + pointerType: updateGPoint.type, + position: getPointRelativeToAbsolute( releasePoint, tracker.element ), + buttons: pointsList.buttons, + insideElementPressed: updateGPoint.insideElementPressed, + insideElementReleased: updateGPoint.insideElement, + isTouchEvent: updateGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } + } + } + + return releaseCapture; + } + + + /** + * Call when pointer(s) change coordinates, button state, pressure, tilt, or contact geometry (e.g. width and height) + * + * @function + * @private + * @inner + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the MouseTracker instance. + * @param {Object} event + * A reference to the originating DOM event. + * @param {Array.} gPoints + * Gesture points associated with the event. + */ + function updatePointersMove( tracker, event, gPoints ) { + var delegate = THIS[ tracker.hash ], + pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ), + i, + gPointCount = gPoints.length, + curGPoint, + updateGPoint, + gPointArray, + delta, + propagate; + + if ( typeof event.buttons !== 'undefined' ) { + pointsList.buttons = event.buttons; + } + + for ( i = 0; i < gPointCount; i++ ) { + curGPoint = gPoints[ i ]; + updateGPoint = pointsList.getById( curGPoint.id ); + + if ( updateGPoint ) { + // Already tracking the pointer...update it + if ( curGPoint.hasOwnProperty( 'isPrimary' ) ) { + updateGPoint.isPrimary = curGPoint.isPrimary; + } + updateGPoint.lastPos = updateGPoint.currentPos; + updateGPoint.lastTime = updateGPoint.currentTime; + updateGPoint.currentPos = curGPoint.currentPos; + updateGPoint.currentTime = curGPoint.currentTime; + } else { + // Initialize for tracking and add to the tracking list (no pointerover or pointerdown event occurred before this) + curGPoint.captured = false; + curGPoint.insideElementPressed = false; + curGPoint.insideElement = true; + startTrackingPointer( pointsList, curGPoint ); + } + } + + // Stop (mouse only) + if ( tracker.stopHandler && gPoints[ 0 ].type === 'mouse' ) { + clearTimeout( tracker.stopTimeOut ); + tracker.stopTimeOut = setTimeout( function() { + handlePointerStop( tracker, event, gPoints[ 0 ].type ); + }, tracker.stopDelay ); + } + + if ( pointsList.contacts === 0 ) { + // Move (no contacts: hovering mouse or other hover-capable device) + if ( tracker.moveHandler ) { + propagate = tracker.moveHandler( + { + eventSource: tracker, + pointerType: gPoints[ 0 ].type, + position: getPointRelativeToAbsolute( gPoints[ 0 ].currentPos, tracker.element ), + buttons: pointsList.buttons, + isTouchEvent: gPoints[ 0 ].type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } else if ( pointsList.contacts === 1 ) { + // Move (1 contact) + if ( tracker.moveHandler ) { + updateGPoint = pointsList.asArray()[ 0 ]; + propagate = tracker.moveHandler( + { + eventSource: tracker, + pointerType: updateGPoint.type, + position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ), + buttons: pointsList.buttons, + isTouchEvent: updateGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + + // Drag + if ( tracker.dragHandler ) { + updateGPoint = pointsList.asArray()[ 0 ]; + delta = updateGPoint.currentPos.minus( updateGPoint.lastPos ); + propagate = tracker.dragHandler( + { + eventSource: tracker, + pointerType: updateGPoint.type, + position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ), + buttons: pointsList.buttons, + delta: delta, + speed: updateGPoint.speed, + direction: updateGPoint.direction, + shift: event.shiftKey, + isTouchEvent: updateGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } else if ( pointsList.contacts === 2 ) { + // Move (2 contacts, use center) + if ( tracker.moveHandler ) { + gPointArray = pointsList.asArray(); + propagate = tracker.moveHandler( + { + eventSource: tracker, + pointerType: gPointArray[ 0 ].type, + position: getPointRelativeToAbsolute( getCenterPoint( gPointArray[ 0 ].currentPos, gPointArray[ 1 ].currentPos ), tracker.element ), + buttons: pointsList.buttons, + isTouchEvent: gPointArray[ 0 ].type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + + // Pinch + if ( tracker.pinchHandler && gPoints[ 0 ].type === 'touch' ) { + delta = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos ); + if ( delta != delegate.currentPinchDist ) { + delegate.lastPinchDist = delegate.currentPinchDist; + delegate.currentPinchDist = delta; + delegate.lastPinchCenter = delegate.currentPinchCenter; + delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos ); + propagate = tracker.pinchHandler( + { + eventSource: tracker, + pointerType: 'touch', + gesturePoints: delegate.pinchGPoints, + lastCenter: getPointRelativeToAbsolute( delegate.lastPinchCenter, tracker.element ), + center: getPointRelativeToAbsolute( delegate.currentPinchCenter, tracker.element ), + lastDistance: delegate.lastPinchDist, + distance: delegate.currentPinchDist, + shift: event.shiftKey, + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } + } + } + + + /** + * @function + * @private + * @inner + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the MouseTracker instance. + * @param {Object} event + * A reference to the originating DOM event. + * @param {Array.} gPoints + * Gesture points associated with the event. + */ + function updatePointersCancel( tracker, event, gPoints ) { + updatePointersUp( tracker, event, gPoints, 0 ); + updatePointersExit( tracker, event, gPoints ); + } + + + /** + * @private + * @inner + */ + function handlePointerStop( tracker, originalMoveEvent, pointerType ) { + if ( tracker.stopHandler ) { + tracker.stopHandler( { + eventSource: tracker, + pointerType: pointerType, + position: getMouseRelative( originalMoveEvent, tracker.element ), + buttons: tracker.getActivePointersListByType( pointerType ).buttons, + isTouchEvent: pointerType === 'touch', + originalEvent: originalMoveEvent, + preventDefaultAction: false, + userData: tracker.userData + } ); + } + } + + /** + * True if inside an iframe, otherwise false. + * @member {Boolean} isInIframe + * @private + * @inner + */ + var isInIframe = (function() { + try { + return window.self !== window.top; + } catch (e) { + return true; + } + })(); + + /** + * @function + * @private + * @inner + * @returns {Boolean} True if the target has access rights to events, otherwise false. + */ + function canAccessEvents (target) { + try { + return target.addEventListener && target.removeEventListener; + } catch (e) { + return false; + } + } + +}(OpenSeadragon)); + +/* + * OpenSeadragon - Control + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * An enumeration of supported locations where controls can be anchored. + * The anchoring is always relative to the container. + * @member ControlAnchor + * @memberof OpenSeadragon + * @static + * @type {Object} + * @property {Number} NONE + * @property {Number} TOP_LEFT + * @property {Number} TOP_RIGHT + * @property {Number} BOTTOM_LEFT + * @property {Number} BOTTOM_RIGHT + * @property {Number} ABSOLUTE + */ +$.ControlAnchor = { + NONE: 0, + TOP_LEFT: 1, + TOP_RIGHT: 2, + BOTTOM_RIGHT: 3, + BOTTOM_LEFT: 4, + ABSOLUTE: 5 +}; + +/** + * @class Control + * @classdesc A Control represents any interface element which is meant to allow the user + * to interact with the zoomable interface. Any control can be anchored to any + * element. + * + * @memberof OpenSeadragon + * @param {Element} element - the control element to be anchored in the container. + * @param {Object } options - All required and optional settings for configuring a control element. + * @param {OpenSeadragon.ControlAnchor} [options.anchor=OpenSeadragon.ControlAnchor.NONE] - the position of the control + * relative to the container. + * @param {Boolean} [options.attachToViewer=true] - Whether the control should be added directly to the viewer, or + * directly to the container + * @param {Boolean} [options.autoFade=true] - Whether the control should have the autofade behavior + * @param {Element} container - the element to control will be anchored too. + */ +$.Control = function ( element, options, container ) { + var parent = element.parentNode; + if (typeof options === 'number') + { + $.console.error("Passing an anchor directly into the OpenSeadragon.Control constructor is deprecated; " + + "please use an options object instead. " + + "Support for this deprecated variant is scheduled for removal in December 2013"); + options = {anchor: options}; + } + options.attachToViewer = (typeof options.attachToViewer === 'undefined') ? true : options.attachToViewer; + /** + * True if the control should have autofade behavior. + * @member {Boolean} autoFade + * @memberof OpenSeadragon.Control# + */ + this.autoFade = (typeof options.autoFade === 'undefined') ? true : options.autoFade; + /** + * The element providing the user interface with some type of control (e.g. a zoom-in button). + * @member {Element} element + * @memberof OpenSeadragon.Control# + */ + this.element = element; + /** + * The position of the Control relative to its container. + * @member {OpenSeadragon.ControlAnchor} anchor + * @memberof OpenSeadragon.Control# + */ + this.anchor = options.anchor; + /** + * The Control's containing element. + * @member {Element} container + * @memberof OpenSeadragon.Control# + */ + this.container = container; + /** + * A neutral element surrounding the control element. + * @member {Element} wrapper + * @memberof OpenSeadragon.Control# + */ + if ( this.anchor == $.ControlAnchor.ABSOLUTE ) { + this.wrapper = $.makeNeutralElement( "div" ); + this.wrapper.style.position = "absolute"; + this.wrapper.style.top = typeof (options.top) == "number" ? (options.top + 'px') : options.top; + this.wrapper.style.left = typeof (options.left) == "number" ? (options.left + 'px') : options.left; + this.wrapper.style.height = typeof (options.height) == "number" ? (options.height + 'px') : options.height; + this.wrapper.style.width = typeof (options.width) == "number" ? (options.width + 'px') : options.width; + this.wrapper.style.margin = "0px"; + this.wrapper.style.padding = "0px"; + + this.element.style.position = "relative"; + this.element.style.top = "0px"; + this.element.style.left = "0px"; + this.element.style.height = "100%"; + this.element.style.width = "100%"; + } else { + this.wrapper = $.makeNeutralElement( "div" ); + this.wrapper.style.display = "inline-block"; + if ( this.anchor == $.ControlAnchor.NONE ) { + // IE6 fix + this.wrapper.style.width = this.wrapper.style.height = "100%"; + } + } + this.wrapper.appendChild( this.element ); + + if (options.attachToViewer ) { + if ( this.anchor == $.ControlAnchor.TOP_RIGHT || + this.anchor == $.ControlAnchor.BOTTOM_RIGHT ) { + this.container.insertBefore( + this.wrapper, + this.container.firstChild + ); + } else { + this.container.appendChild( this.wrapper ); + } + } else { + parent.appendChild( this.wrapper ); + } +}; + +/** @lends OpenSeadragon.Control.prototype */ +$.Control.prototype = { + + /** + * Removes the control from the container. + * @function + */ + destroy: function() { + this.wrapper.removeChild( this.element ); + this.container.removeChild( this.wrapper ); + }, + + /** + * Determines if the control is currently visible. + * @function + * @return {Boolean} true if currenly visible, false otherwise. + */ + isVisible: function() { + return this.wrapper.style.display != "none"; + }, + + /** + * Toggles the visibility of the control. + * @function + * @param {Boolean} visible - true to make visible, false to hide. + */ + setVisible: function( visible ) { + this.wrapper.style.display = visible ? + ( this.anchor == $.ControlAnchor.ABSOLUTE ? 'block' : 'inline-block' ) : + "none"; + }, + + /** + * Sets the opacity level for the control. + * @function + * @param {Number} opactiy - a value between 1 and 0 inclusively. + */ + setOpacity: function( opacity ) { + if ( this.element[ $.SIGNAL ] && $.Browser.vendor == $.BROWSERS.IE ) { + $.setElementOpacity( this.element, opacity, true ); + } else { + $.setElementOpacity( this.wrapper, opacity, true ); + } + } +}; + +}( OpenSeadragon )); + +/* + * OpenSeadragon - ControlDock + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + /** + * @class ControlDock + * @classdesc Provides a container element (a <form> element) with support for the layout of control elements. + * + * @memberof OpenSeadragon + */ + $.ControlDock = function( options ){ + var layouts = [ 'topleft', 'topright', 'bottomright', 'bottomleft'], + layout, + i; + + $.extend( true, this, { + id: 'controldock-' + $.now() + '-' + Math.floor(Math.random() * 1000000), + container: $.makeNeutralElement( 'div' ), + controls: [] + }, options ); + + // Disable the form's submit; otherwise button clicks and return keys + // can trigger it. + this.container.onsubmit = function() { + return false; + }; + + if( this.element ){ + this.element = $.getElement( this.element ); + this.element.appendChild( this.container ); + this.element.style.position = 'relative'; + this.container.style.width = '100%'; + this.container.style.height = '100%'; + } + + for( i = 0; i < layouts.length; i++ ){ + layout = layouts[ i ]; + this.controls[ layout ] = $.makeNeutralElement( "div" ); + this.controls[ layout ].style.position = 'absolute'; + if ( layout.match( 'left' ) ){ + this.controls[ layout ].style.left = '0px'; + } + if ( layout.match( 'right' ) ){ + this.controls[ layout ].style.right = '0px'; + } + if ( layout.match( 'top' ) ){ + this.controls[ layout ].style.top = '0px'; + } + if ( layout.match( 'bottom' ) ){ + this.controls[ layout ].style.bottom = '0px'; + } + } + + this.container.appendChild( this.controls.topleft ); + this.container.appendChild( this.controls.topright ); + this.container.appendChild( this.controls.bottomright ); + this.container.appendChild( this.controls.bottomleft ); + }; + + /** @lends OpenSeadragon.ControlDock.prototype */ + $.ControlDock.prototype = { + + /** + * @function + */ + addControl: function ( element, controlOptions ) { + element = $.getElement( element ); + var div = null; + + if ( getControlIndex( this, element ) >= 0 ) { + return; // they're trying to add a duplicate control + } + + switch ( controlOptions.anchor ) { + case $.ControlAnchor.TOP_RIGHT: + div = this.controls.topright; + element.style.position = "relative"; + element.style.paddingRight = "0px"; + element.style.paddingTop = "0px"; + break; + case $.ControlAnchor.BOTTOM_RIGHT: + div = this.controls.bottomright; + element.style.position = "relative"; + element.style.paddingRight = "0px"; + element.style.paddingBottom = "0px"; + break; + case $.ControlAnchor.BOTTOM_LEFT: + div = this.controls.bottomleft; + element.style.position = "relative"; + element.style.paddingLeft = "0px"; + element.style.paddingBottom = "0px"; + break; + case $.ControlAnchor.TOP_LEFT: + div = this.controls.topleft; + element.style.position = "relative"; + element.style.paddingLeft = "0px"; + element.style.paddingTop = "0px"; + break; + case $.ControlAnchor.ABSOLUTE: + div = this.container; + element.style.margin = "0px"; + element.style.padding = "0px"; + break; + default: + case $.ControlAnchor.NONE: + div = this.container; + element.style.margin = "0px"; + element.style.padding = "0px"; + break; + } + + this.controls.push( + new $.Control( element, controlOptions, div ) + ); + element.style.display = "inline-block"; + }, + + + /** + * @function + * @return {OpenSeadragon.ControlDock} Chainable. + */ + removeControl: function ( element ) { + element = $.getElement( element ); + var i = getControlIndex( this, element ); + + if ( i >= 0 ) { + this.controls[ i ].destroy(); + this.controls.splice( i, 1 ); + } + + return this; + }, + + /** + * @function + * @return {OpenSeadragon.ControlDock} Chainable. + */ + clearControls: function () { + while ( this.controls.length > 0 ) { + this.controls.pop().destroy(); + } + + return this; + }, + + + /** + * @function + * @return {Boolean} + */ + areControlsEnabled: function () { + var i; + + for ( i = this.controls.length - 1; i >= 0; i-- ) { + if ( this.controls[ i ].isVisible() ) { + return true; + } + } + + return false; + }, + + + /** + * @function + * @return {OpenSeadragon.ControlDock} Chainable. + */ + setControlsEnabled: function( enabled ) { + var i; + + for ( i = this.controls.length - 1; i >= 0; i-- ) { + this.controls[ i ].setVisible( enabled ); + } + + return this; + } + + }; + + + /////////////////////////////////////////////////////////////////////////////// + // Utility methods + /////////////////////////////////////////////////////////////////////////////// + function getControlIndex( dock, element ) { + var controls = dock.controls, + i; + + for ( i = controls.length - 1; i >= 0; i-- ) { + if ( controls[ i ].element == element ) { + return i; + } + } + + return -1; + } + +}( OpenSeadragon )); + +/* + * OpenSeadragon - Placement + * + * Copyright (C) 2010-2016 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function($) { + + /** + * An enumeration of positions to anchor an element. + * @member Placement + * @memberOf OpenSeadragon + * @static + * @readonly + * @property {OpenSeadragon.Placement} CENTER + * @property {OpenSeadragon.Placement} TOP_LEFT + * @property {OpenSeadragon.Placement} TOP + * @property {OpenSeadragon.Placement} TOP_RIGHT + * @property {OpenSeadragon.Placement} RIGHT + * @property {OpenSeadragon.Placement} BOTTOM_RIGHT + * @property {OpenSeadragon.Placement} BOTTOM + * @property {OpenSeadragon.Placement} BOTTOM_LEFT + * @property {OpenSeadragon.Placement} LEFT + */ + $.Placement = $.freezeObject({ + CENTER: 0, + TOP_LEFT: 1, + TOP: 2, + TOP_RIGHT: 3, + RIGHT: 4, + BOTTOM_RIGHT: 5, + BOTTOM: 6, + BOTTOM_LEFT: 7, + LEFT: 8, + properties: { + 0: { + isLeft: false, + isHorizontallyCentered: true, + isRight: false, + isTop: false, + isVerticallyCentered: true, + isBottom: false + }, + 1: { + isLeft: true, + isHorizontallyCentered: false, + isRight: false, + isTop: true, + isVerticallyCentered: false, + isBottom: false + }, + 2: { + isLeft: false, + isHorizontallyCentered: true, + isRight: false, + isTop: true, + isVerticallyCentered: false, + isBottom: false + }, + 3: { + isLeft: false, + isHorizontallyCentered: false, + isRight: true, + isTop: true, + isVerticallyCentered: false, + isBottom: false + }, + 4: { + isLeft: false, + isHorizontallyCentered: false, + isRight: true, + isTop: false, + isVerticallyCentered: true, + isBottom: false + }, + 5: { + isLeft: false, + isHorizontallyCentered: false, + isRight: true, + isTop: false, + isVerticallyCentered: false, + isBottom: true + }, + 6: { + isLeft: false, + isHorizontallyCentered: true, + isRight: false, + isTop: false, + isVerticallyCentered: false, + isBottom: true + }, + 7: { + isLeft: true, + isHorizontallyCentered: false, + isRight: false, + isTop: false, + isVerticallyCentered: false, + isBottom: true + }, + 8: { + isLeft: true, + isHorizontallyCentered: false, + isRight: false, + isTop: false, + isVerticallyCentered: true, + isBottom: false + } + } + }); + +}(OpenSeadragon)); + +/* + * OpenSeadragon - Viewer + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +// dictionary from hash to private properties +var THIS = {}; +var nextHash = 1; + +/** + * + * The main point of entry into creating a zoomable image on the page.
      + *
      + * We have provided an idiomatic javascript constructor which takes + * a single object, but still support the legacy positional arguments.
      + *
      + * The options below are given in order that they appeared in the constructor + * as arguments and we translate a positional call into an idiomatic call.
      + *
      + * To create a viewer, you can use either of this methods:
      + *
        + *
      • var viewer = new OpenSeadragon.Viewer(options);
      • + *
      • var viewer = OpenSeadragon(options);
      • + *
      + * @class Viewer + * @classdesc The main OpenSeadragon viewer class. + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.EventSource + * @extends OpenSeadragon.ControlDock + * @param {OpenSeadragon.Options} options - Viewer options. + * + **/ +$.Viewer = function( options ) { + + var args = arguments, + _this = this, + i; + + + //backward compatibility for positional args while prefering more + //idiomatic javascript options object as the only argument + if( !$.isPlainObject( options ) ){ + options = { + id: args[ 0 ], + xmlPath: args.length > 1 ? args[ 1 ] : undefined, + prefixUrl: args.length > 2 ? args[ 2 ] : undefined, + controls: args.length > 3 ? args[ 3 ] : undefined, + overlays: args.length > 4 ? args[ 4 ] : undefined + }; + } + + //options.config and the general config argument are deprecated + //in favor of the more direct specification of optional settings + //being pass directly on the options object + if ( options.config ){ + $.extend( true, options, options.config ); + delete options.config; + } + + //Public properties + //Allow the options object to override global defaults + $.extend( true, this, { + + //internal state and dom identifiers + id: options.id, + hash: options.hash || nextHash++, + /** + * Index for page to be shown first next time open() is called (only used in sequenceMode). + * @member {Number} initialPage + * @memberof OpenSeadragon.Viewer# + */ + initialPage: 0, + + //dom nodes + /** + * The parent element of this Viewer instance, passed in when the Viewer was created. + * @member {Element} element + * @memberof OpenSeadragon.Viewer# + */ + element: null, + /** + * A <div> element (provided by {@link OpenSeadragon.ControlDock}), the base element of this Viewer instance.

      + * Child element of {@link OpenSeadragon.Viewer#element}. + * @member {Element} container + * @memberof OpenSeadragon.Viewer# + */ + container: null, + /** + * A <div> element, the element where user-input events are handled for panning and zooming.

      + * Child element of {@link OpenSeadragon.Viewer#container}, + * positioned on top of {@link OpenSeadragon.Viewer#keyboardCommandArea}.

      + * The parent of {@link OpenSeadragon.Drawer#canvas} instances. + * @member {Element} canvas + * @memberof OpenSeadragon.Viewer# + */ + canvas: null, + + // Overlays list. An overlay allows to add html on top of the viewer. + overlays: [], + // Container inside the canvas where overlays are drawn. + overlaysContainer: null, + + //private state properties + previousBody: [], + + //This was originally initialized in the constructor and so could never + //have anything in it. now it can because we allow it to be specified + //in the options and is only empty by default if not specified. Also + //this array was returned from get_controls which I find confusing + //since this object has a controls property which is treated in other + //functions like clearControls. I'm removing the accessors. + customControls: [], + + //These are originally not part options but declared as members + //in initialize. It's still considered idiomatic to put them here + source: null, + /** + * Handles rendering of tiles in the viewer. Created for each TileSource opened. + * @member {OpenSeadragon.Drawer} drawer + * @memberof OpenSeadragon.Viewer# + */ + drawer: null, + world: null, + /** + * Handles coordinate-related functionality - zoom, pan, rotation, etc. Created for each TileSource opened. + * @member {OpenSeadragon.Viewport} viewport + * @memberof OpenSeadragon.Viewer# + */ + viewport: null, + /** + * @member {OpenSeadragon.Navigator} navigator + * @memberof OpenSeadragon.Viewer# + */ + navigator: null, + + //A collection viewport is a separate viewport used to provide + //simultaneous rendering of sets of tiles + collectionViewport: null, + collectionDrawer: null, + + //UI image resources + //TODO: rename navImages to uiImages + navImages: null, + + //interface button controls + buttons: null, + + //TODO: this is defunct so safely remove it + profiler: null + + }, $.DEFAULT_SETTINGS, options ); + + if ( typeof( this.hash) === "undefined" ) { + throw new Error("A hash must be defined, either by specifying options.id or options.hash."); + } + if ( typeof( THIS[ this.hash ] ) !== "undefined" ) { + // We don't want to throw an error here, as the user might have discarded + // the previous viewer with the same hash and now want to recreate it. + $.console.warn("Hash " + this.hash + " has already been used."); + } + + //Private state properties + THIS[ this.hash ] = { + "fsBoundsDelta": new $.Point( 1, 1 ), + "prevContainerSize": null, + "animating": false, + "forceRedraw": false, + "mouseInside": false, + "group": null, + // whether we should be continuously zooming + "zooming": false, + // how much we should be continuously zooming by + "zoomFactor": null, + "lastZoomTime": null, + "fullPage": false, + "onfullscreenchange": null + }; + + this._sequenceIndex = 0; + this._firstOpen = true; + this._updateRequestId = null; + this._loadQueue = []; + this.currentOverlays = []; + + this._lastScrollTime = $.now(); // variable used to help normalize the scroll event speed of different devices + + //Inherit some behaviors and properties + $.EventSource.call( this ); + + this.addHandler( 'open-failed', function ( event ) { + var msg = $.getString( "Errors.OpenFailed", event.eventSource, event.message); + _this._showMessage( msg ); + }); + + $.ControlDock.call( this, options ); + + //Deal with tile sources + if (this.xmlPath) { + //Deprecated option. Now it is preferred to use the tileSources option + this.tileSources = [ this.xmlPath ]; + } + + this.element = this.element || document.getElementById( this.id ); + this.canvas = $.makeNeutralElement( "div" ); + + this.canvas.className = "openseadragon-canvas"; + (function( style ){ + style.width = "100%"; + style.height = "100%"; + style.overflow = "hidden"; + style.position = "absolute"; + style.top = "0px"; + style.left = "0px"; + }(this.canvas.style)); + $.setElementTouchActionNone( this.canvas ); + if (options.tabIndex !== "") { + this.canvas.tabIndex = (options.tabIndex === undefined ? 0 : options.tabIndex); + } + + //the container is created through applying the ControlDock constructor above + this.container.className = "openseadragon-container"; + (function( style ){ + style.width = "100%"; + style.height = "100%"; + style.position = "relative"; + style.overflow = "hidden"; + style.left = "0px"; + style.top = "0px"; + style.textAlign = "left"; // needed to protect against + }( this.container.style )); + + this.container.insertBefore( this.canvas, this.container.firstChild ); + this.element.appendChild( this.container ); + + //Used for toggling between fullscreen and default container size + //TODO: these can be closure private and shared across Viewer + // instances. + this.bodyWidth = document.body.style.width; + this.bodyHeight = document.body.style.height; + this.bodyOverflow = document.body.style.overflow; + this.docOverflow = document.documentElement.style.overflow; + + this.innerTracker = new $.MouseTracker({ + element: this.canvas, + startDisabled: !this.mouseNavEnabled, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + dblClickTimeThreshold: this.dblClickTimeThreshold, + dblClickDistThreshold: this.dblClickDistThreshold, + keyDownHandler: $.delegate( this, onCanvasKeyDown ), + keyHandler: $.delegate( this, onCanvasKeyPress ), + clickHandler: $.delegate( this, onCanvasClick ), + dblClickHandler: $.delegate( this, onCanvasDblClick ), + dragHandler: $.delegate( this, onCanvasDrag ), + dragEndHandler: $.delegate( this, onCanvasDragEnd ), + enterHandler: $.delegate( this, onCanvasEnter ), + exitHandler: $.delegate( this, onCanvasExit ), + pressHandler: $.delegate( this, onCanvasPress ), + releaseHandler: $.delegate( this, onCanvasRelease ), + nonPrimaryPressHandler: $.delegate( this, onCanvasNonPrimaryPress ), + nonPrimaryReleaseHandler: $.delegate( this, onCanvasNonPrimaryRelease ), + scrollHandler: $.delegate( this, onCanvasScroll ), + pinchHandler: $.delegate( this, onCanvasPinch ) + }); + + this.outerTracker = new $.MouseTracker({ + element: this.container, + startDisabled: !this.mouseNavEnabled, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + dblClickTimeThreshold: this.dblClickTimeThreshold, + dblClickDistThreshold: this.dblClickDistThreshold, + enterHandler: $.delegate( this, onContainerEnter ), + exitHandler: $.delegate( this, onContainerExit ) + }); + + if( this.toolbar ){ + this.toolbar = new $.ControlDock({ element: this.toolbar }); + } + + this.bindStandardControls(); + + THIS[ this.hash ].prevContainerSize = _getSafeElemSize( this.container ); + + // Create the world + this.world = new $.World({ + viewer: this + }); + + this.world.addHandler('add-item', function(event) { + // For backwards compatibility, we maintain the source property + _this.source = _this.world.getItemAt(0).source; + + THIS[ _this.hash ].forceRedraw = true; + + if (!_this._updateRequestId) { + _this._updateRequestId = scheduleUpdate( _this, updateMulti ); + } + }); + + this.world.addHandler('remove-item', function(event) { + // For backwards compatibility, we maintain the source property + if (_this.world.getItemCount()) { + _this.source = _this.world.getItemAt(0).source; + } else { + _this.source = null; + } + + THIS[ _this.hash ].forceRedraw = true; + }); + + this.world.addHandler('metrics-change', function(event) { + if (_this.viewport) { + _this.viewport._setContentBounds(_this.world.getHomeBounds(), _this.world.getContentFactor()); + } + }); + + this.world.addHandler('item-index-change', function(event) { + // For backwards compatibility, we maintain the source property + _this.source = _this.world.getItemAt(0).source; + }); + + // Create the viewport + this.viewport = new $.Viewport({ + containerSize: THIS[ this.hash ].prevContainerSize, + springStiffness: this.springStiffness, + animationTime: this.animationTime, + minZoomImageRatio: this.minZoomImageRatio, + maxZoomPixelRatio: this.maxZoomPixelRatio, + visibilityRatio: this.visibilityRatio, + wrapHorizontal: this.wrapHorizontal, + wrapVertical: this.wrapVertical, + defaultZoomLevel: this.defaultZoomLevel, + minZoomLevel: this.minZoomLevel, + maxZoomLevel: this.maxZoomLevel, + viewer: this, + degrees: this.degrees, + navigatorRotate: this.navigatorRotate, + homeFillsViewer: this.homeFillsViewer, + margins: this.viewportMargins + }); + + this.viewport._setContentBounds(this.world.getHomeBounds(), this.world.getContentFactor()); + + // Create the image loader + this.imageLoader = new $.ImageLoader({ + jobLimit: this.imageLoaderLimit, + timeout: options.timeout + }); + + // Create the tile cache + this.tileCache = new $.TileCache({ + maxImageCacheCount: this.maxImageCacheCount + }); + + // Create the drawer + this.drawer = new $.Drawer({ + viewer: this, + viewport: this.viewport, + element: this.canvas, + debugGridColor: this.debugGridColor + }); + + // Overlay container + this.overlaysContainer = $.makeNeutralElement( "div" ); + this.canvas.appendChild( this.overlaysContainer ); + + // Now that we have a drawer, see if it supports rotate. If not we need to remove the rotate buttons + if (!this.drawer.canRotate()) { + // Disable/remove the rotate left/right buttons since they aren't supported + if (this.rotateLeft) { + i = this.buttons.buttons.indexOf(this.rotateLeft); + this.buttons.buttons.splice(i, 1); + this.buttons.element.removeChild(this.rotateLeft.element); + } + if (this.rotateRight) { + i = this.buttons.buttons.indexOf(this.rotateRight); + this.buttons.buttons.splice(i, 1); + this.buttons.element.removeChild(this.rotateRight.element); + } + } + + //Instantiate a navigator if configured + if ( this.showNavigator){ + this.navigator = new $.Navigator({ + id: this.navigatorId, + position: this.navigatorPosition, + sizeRatio: this.navigatorSizeRatio, + maintainSizeRatio: this.navigatorMaintainSizeRatio, + top: this.navigatorTop, + left: this.navigatorLeft, + width: this.navigatorWidth, + height: this.navigatorHeight, + autoResize: this.navigatorAutoResize, + autoFade: this.navigatorAutoFade, + prefixUrl: this.prefixUrl, + viewer: this, + navigatorRotate: this.navigatorRotate, + crossOriginPolicy: this.crossOriginPolicy + }); + } + + // Sequence mode + if (this.sequenceMode) { + this.bindSequenceControls(); + } + + // Open initial tilesources + if (this.tileSources) { + this.open( this.tileSources ); + } + + // Add custom controls + for ( i = 0; i < this.customControls.length; i++ ) { + this.addControl( + this.customControls[ i ].id, + {anchor: this.customControls[ i ].anchor} + ); + } + + // Initial fade out + $.requestAnimationFrame( function(){ + beginControlsAutoHide( _this ); + } ); +}; + +$.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, /** @lends OpenSeadragon.Viewer.prototype */{ + + + /** + * @function + * @return {Boolean} + */ + isOpen: function () { + return !!this.world.getItemCount(); + }, + + // deprecated + openDzi: function ( dzi ) { + $.console.error( "[Viewer.openDzi] this function is deprecated; use Viewer.open() instead." ); + return this.open( dzi ); + }, + + // deprecated + openTileSource: function ( tileSource ) { + $.console.error( "[Viewer.openTileSource] this function is deprecated; use Viewer.open() instead." ); + return this.open( tileSource ); + }, + + /** + * Open tiled images into the viewer, closing any others. + * @function + * @param {Array|String|Object|Function} tileSources - This can be a TiledImage + * specifier, a TileSource specifier, or an array of either. A TiledImage specifier + * is the same as the options parameter for {@link OpenSeadragon.Viewer#addTiledImage}, + * except for the index property; images are added in sequence. + * A TileSource specifier is anything you could pass as the tileSource property + * of the options parameter for {@link OpenSeadragon.Viewer#addTiledImage}. + * @param {Number} initialPage - If sequenceMode is true, display this page initially + * for the given tileSources. If specified, will overwrite the Viewer's existing initialPage property. + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:open + * @fires OpenSeadragon.Viewer.event:open-failed + */ + open: function (tileSources, initialPage) { + var _this = this; + + this.close(); + + if (!tileSources) { + return; + } + + if (this.sequenceMode && $.isArray(tileSources)) { + if (this.referenceStrip) { + this.referenceStrip.destroy(); + this.referenceStrip = null; + } + + if (typeof initialPage != 'undefined' && !isNaN(initialPage)) { + this.initialPage = initialPage; + } + + this.tileSources = tileSources; + this._sequenceIndex = Math.max(0, Math.min(this.tileSources.length - 1, this.initialPage)); + if (this.tileSources.length) { + this.open(this.tileSources[this._sequenceIndex]); + + if ( this.showReferenceStrip ){ + this.addReferenceStrip(); + } + } + + this._updateSequenceButtons( this._sequenceIndex ); + return; + } + + if (!$.isArray(tileSources)) { + tileSources = [tileSources]; + } + + if (!tileSources.length) { + return; + } + + this._opening = true; + + var expected = tileSources.length; + var successes = 0; + var failures = 0; + var failEvent; + + var checkCompletion = function() { + if (successes + failures === expected) { + if (successes) { + if (_this._firstOpen || !_this.preserveViewport) { + _this.viewport.goHome( true ); + _this.viewport.update(); + } + + _this._firstOpen = false; + + var source = tileSources[0]; + if (source.tileSource) { + source = source.tileSource; + } + + // Global overlays + if( _this.overlays && !_this.preserveOverlays ){ + for ( var i = 0; i < _this.overlays.length; i++ ) { + _this.currentOverlays[ i ] = getOverlayObject( _this, _this.overlays[ i ] ); + } + } + + _this._drawOverlays(); + _this._opening = false; + + /** + * Raised when the viewer has opened and loaded one or more TileSources. + * + * @event open + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {OpenSeadragon.TileSource} source - The tile source that was opened. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + // TODO: what if there are multiple sources? + _this.raiseEvent( 'open', { source: source } ); + } else { + _this._opening = false; + + /** + * Raised when an error occurs loading a TileSource. + * + * @event open-failed + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {String} message - Information about what failed. + * @property {String} source - The tile source that failed. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( 'open-failed', failEvent ); + } + } + }; + + var doOne = function(options) { + if (!$.isPlainObject(options) || !options.tileSource) { + options = { + tileSource: options + }; + } + + if (options.index !== undefined) { + $.console.error('[Viewer.open] setting indexes here is not supported; use addTiledImage instead'); + delete options.index; + } + + if (options.collectionImmediately === undefined) { + options.collectionImmediately = true; + } + + var originalSuccess = options.success; + options.success = function(event) { + successes++; + + // TODO: now that options has other things besides tileSource, the overlays + // should probably be at the options level, not the tileSource level. + if (options.tileSource.overlays) { + for (var i = 0; i < options.tileSource.overlays.length; i++) { + _this.addOverlay(options.tileSource.overlays[i]); + } + } + + if (originalSuccess) { + originalSuccess(event); + } + + checkCompletion(); + }; + + var originalError = options.error; + options.error = function(event) { + failures++; + + if (!failEvent) { + failEvent = event; + } + + if (originalError) { + originalError(event); + } + + checkCompletion(); + }; + + _this.addTiledImage(options); + }; + + // TileSources + for (var i = 0; i < tileSources.length; i++) { + doOne(tileSources[i]); + } + + return this; + }, + + + /** + * @function + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:close + */ + close: function ( ) { + if ( !THIS[ this.hash ] ) { + //this viewer has already been destroyed: returning immediately + return this; + } + + this._opening = false; + + if ( this.navigator ) { + this.navigator.close(); + } + + if (!this.preserveOverlays) { + this.clearOverlays(); + this.overlaysContainer.innerHTML = ""; + } + + THIS[ this.hash ].animating = false; + this.world.removeAll(); + this.imageLoader.clear(); + + /** + * Raised when the viewer is closed (see {@link OpenSeadragon.Viewer#close}). + * + * @event close + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'close' ); + + return this; + }, + + + /** + * Function to destroy the viewer and clean up everything created by OpenSeadragon. + * + * Example: + * var viewer = OpenSeadragon({ + * [...] + * }); + * + * //when you are done with the viewer: + * viewer.destroy(); + * viewer = null; //important + * + * @function + */ + destroy: function( ) { + if ( !THIS[ this.hash ] ) { + //this viewer has already been destroyed: returning immediately + return; + } + + this.close(); + + this.clearOverlays(); + this.overlaysContainer.innerHTML = ""; + + //TODO: implement this... + //this.unbindSequenceControls() + //this.unbindStandardControls() + + if (this.referenceStrip) { + this.referenceStrip.destroy(); + this.referenceStrip = null; + } + + if ( this._updateRequestId !== null ) { + $.cancelAnimationFrame( this._updateRequestId ); + this._updateRequestId = null; + } + + if ( this.drawer ) { + this.drawer.destroy(); + } + + this.removeAllHandlers(); + + // Go through top element (passed to us) and remove all children + // Use removeChild to make sure it handles SVG or any non-html + // also it performs better - http://jsperf.com/innerhtml-vs-removechild/15 + if (this.element){ + while (this.element.firstChild) { + this.element.removeChild(this.element.firstChild); + } + } + + // destroy the mouse trackers + if (this.innerTracker){ + this.innerTracker.destroy(); + } + if (this.outerTracker){ + this.outerTracker.destroy(); + } + + THIS[ this.hash ] = null; + delete THIS[ this.hash ]; + + // clear all our references to dom objects + this.canvas = null; + this.container = null; + + // clear our reference to the main element - they will need to pass it in again, creating a new viewer + this.element = null; + }, + + /** + * @function + * @return {Boolean} + */ + isMouseNavEnabled: function () { + return this.innerTracker.isTracking(); + }, + + /** + * @function + * @param {Boolean} enabled - true to enable, false to disable + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:mouse-enabled + */ + setMouseNavEnabled: function( enabled ){ + this.innerTracker.setTracking( enabled ); + this.outerTracker.setTracking( enabled ); + /** + * Raised when mouse/touch navigation is enabled or disabled (see {@link OpenSeadragon.Viewer#setMouseNavEnabled}). + * + * @event mouse-enabled + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Boolean} enabled + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'mouse-enabled', { enabled: enabled } ); + return this; + }, + + + /** + * @function + * @return {Boolean} + */ + areControlsEnabled: function () { + var enabled = this.controls.length, + i; + for( i = 0; i < this.controls.length; i++ ){ + enabled = enabled && this.controls[ i ].isVisibile(); + } + return enabled; + }, + + + /** + * Shows or hides the controls (e.g. the default navigation buttons). + * + * @function + * @param {Boolean} true to show, false to hide. + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:controls-enabled + */ + setControlsEnabled: function( enabled ) { + if( enabled ){ + abortControlsAutoHide( this ); + } else { + beginControlsAutoHide( this ); + } + /** + * Raised when the navigation controls are shown or hidden (see {@link OpenSeadragon.Viewer#setControlsEnabled}). + * + * @event controls-enabled + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Boolean} enabled + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'controls-enabled', { enabled: enabled } ); + return this; + }, + + /** + * Turns debugging mode on or off for this viewer. + * + * @function + * @param {Boolean} true to turn debug on, false to turn debug off. + */ + setDebugMode: function(debugMode){ + + for (var i = 0; i < this.world.getItemCount(); i++) { + this.world.getItemAt(i).debugMode = debugMode; + } + + this.debugMode = debugMode; + this.forceRedraw(); + }, + + /** + * @function + * @return {Boolean} + */ + isFullPage: function () { + return THIS[ this.hash ].fullPage; + }, + + + /** + * Toggle full page mode. + * @function + * @param {Boolean} fullPage + * If true, enter full page mode. If false, exit full page mode. + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:pre-full-page + * @fires OpenSeadragon.Viewer.event:full-page + */ + setFullPage: function( fullPage ) { + + var body = document.body, + bodyStyle = body.style, + docStyle = document.documentElement.style, + _this = this, + nodes, + i; + + //dont bother modifying the DOM if we are already in full page mode. + if ( fullPage == this.isFullPage() ) { + return this; + } + + var fullPageEventArgs = { + fullPage: fullPage, + preventDefaultAction: false + }; + /** + * Raised when the viewer is about to change to/from full-page mode (see {@link OpenSeadragon.Viewer#setFullPage}). + * + * @event pre-full-page + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Boolean} fullPage - True if entering full-page mode, false if exiting full-page mode. + * @property {Boolean} preventDefaultAction - Set to true to prevent full-page mode change. Default: false. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'pre-full-page', fullPageEventArgs ); + if ( fullPageEventArgs.preventDefaultAction ) { + return this; + } + + if ( fullPage ) { + + this.elementSize = $.getElementSize( this.element ); + this.pageScroll = $.getPageScroll(); + + this.elementMargin = this.element.style.margin; + this.element.style.margin = "0"; + this.elementPadding = this.element.style.padding; + this.element.style.padding = "0"; + + this.bodyMargin = bodyStyle.margin; + this.docMargin = docStyle.margin; + bodyStyle.margin = "0"; + docStyle.margin = "0"; + + this.bodyPadding = bodyStyle.padding; + this.docPadding = docStyle.padding; + bodyStyle.padding = "0"; + docStyle.padding = "0"; + + this.bodyWidth = bodyStyle.width; + this.docWidth = docStyle.width; + bodyStyle.width = "100%"; + docStyle.width = "100%"; + + this.bodyHeight = bodyStyle.height; + this.docHeight = docStyle.height; + bodyStyle.height = "100%"; + docStyle.height = "100%"; + + //when entering full screen on the ipad it wasnt sufficient to leave + //the body intact as only only the top half of the screen would + //respond to touch events on the canvas, while the bottom half treated + //them as touch events on the document body. Thus we remove and store + //the bodies elements and replace them when we leave full screen. + this.previousBody = []; + THIS[ this.hash ].prevElementParent = this.element.parentNode; + THIS[ this.hash ].prevNextSibling = this.element.nextSibling; + THIS[ this.hash ].prevElementWidth = this.element.style.width; + THIS[ this.hash ].prevElementHeight = this.element.style.height; + nodes = body.childNodes.length; + for ( i = 0; i < nodes; i++ ) { + this.previousBody.push( body.childNodes[ 0 ] ); + body.removeChild( body.childNodes[ 0 ] ); + } + + //If we've got a toolbar, we need to enable the user to use css to + //preserve it in fullpage mode + if ( this.toolbar && this.toolbar.element ) { + //save a reference to the parent so we can put it back + //in the long run we need a better strategy + this.toolbar.parentNode = this.toolbar.element.parentNode; + this.toolbar.nextSibling = this.toolbar.element.nextSibling; + body.appendChild( this.toolbar.element ); + + //Make sure the user has some ability to style the toolbar based + //on the mode + $.addClass( this.toolbar.element, 'fullpage' ); + } + + $.addClass( this.element, 'fullpage' ); + body.appendChild( this.element ); + + this.element.style.height = $.getWindowSize().y + 'px'; + this.element.style.width = $.getWindowSize().x + 'px'; + + if ( this.toolbar && this.toolbar.element ) { + this.element.style.height = ( + $.getElementSize( this.element ).y - $.getElementSize( this.toolbar.element ).y + ) + 'px'; + } + + THIS[ this.hash ].fullPage = true; + + // mouse will be inside container now + $.delegate( this, onContainerEnter )( {} ); + + } else { + + this.element.style.margin = this.elementMargin; + this.element.style.padding = this.elementPadding; + + bodyStyle.margin = this.bodyMargin; + docStyle.margin = this.docMargin; + + bodyStyle.padding = this.bodyPadding; + docStyle.padding = this.docPadding; + + bodyStyle.width = this.bodyWidth; + docStyle.width = this.docWidth; + + bodyStyle.height = this.bodyHeight; + docStyle.height = this.docHeight; + + body.removeChild( this.element ); + nodes = this.previousBody.length; + for ( i = 0; i < nodes; i++ ) { + body.appendChild( this.previousBody.shift() ); + } + + $.removeClass( this.element, 'fullpage' ); + THIS[ this.hash ].prevElementParent.insertBefore( + this.element, + THIS[ this.hash ].prevNextSibling + ); + + //If we've got a toolbar, we need to enable the user to use css to + //reset it to its original state + if ( this.toolbar && this.toolbar.element ) { + body.removeChild( this.toolbar.element ); + + //Make sure the user has some ability to style the toolbar based + //on the mode + $.removeClass( this.toolbar.element, 'fullpage' ); + + this.toolbar.parentNode.insertBefore( + this.toolbar.element, + this.toolbar.nextSibling + ); + delete this.toolbar.parentNode; + delete this.toolbar.nextSibling; + } + + this.element.style.width = THIS[ this.hash ].prevElementWidth; + this.element.style.height = THIS[ this.hash ].prevElementHeight; + + // After exiting fullPage or fullScreen, it can take some time + // before the browser can actually set the scroll. + var restoreScrollCounter = 0; + var restoreScroll = function() { + $.setPageScroll( _this.pageScroll ); + var pageScroll = $.getPageScroll(); + restoreScrollCounter++; + if (restoreScrollCounter < 10 && + (pageScroll.x !== _this.pageScroll.x || + pageScroll.y !== _this.pageScroll.y)) { + $.requestAnimationFrame( restoreScroll ); + } + }; + $.requestAnimationFrame( restoreScroll ); + + THIS[ this.hash ].fullPage = false; + + // mouse will likely be outside now + $.delegate( this, onContainerExit )( { } ); + + } + + if ( this.navigator && this.viewport ) { + this.navigator.update( this.viewport ); + } + + /** + * Raised when the viewer has changed to/from full-page mode (see {@link OpenSeadragon.Viewer#setFullPage}). + * + * @event full-page + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Boolean} fullPage - True if changed to full-page mode, false if exited full-page mode. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'full-page', { fullPage: fullPage } ); + + return this; + }, + + /** + * Toggle full screen mode if supported. Toggle full page mode otherwise. + * @function + * @param {Boolean} fullScreen + * If true, enter full screen mode. If false, exit full screen mode. + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:pre-full-screen + * @fires OpenSeadragon.Viewer.event:full-screen + */ + setFullScreen: function( fullScreen ) { + var _this = this; + + if ( !$.supportsFullScreen ) { + return this.setFullPage( fullScreen ); + } + + if ( $.isFullScreen() === fullScreen ) { + return this; + } + + var fullScreeEventArgs = { + fullScreen: fullScreen, + preventDefaultAction: false + }; + /** + * Raised when the viewer is about to change to/from full-screen mode (see {@link OpenSeadragon.Viewer#setFullScreen}). + * Note: the pre-full-screen event is not raised when the user is exiting + * full-screen mode by pressing the Esc key. In that case, consider using + * the full-screen, pre-full-page or full-page events. + * + * @event pre-full-screen + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Boolean} fullScreen - True if entering full-screen mode, false if exiting full-screen mode. + * @property {Boolean} preventDefaultAction - Set to true to prevent full-screen mode change. Default: false. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'pre-full-screen', fullScreeEventArgs ); + if ( fullScreeEventArgs.preventDefaultAction ) { + return this; + } + + if ( fullScreen ) { + + this.setFullPage( true ); + // If the full page mode is not actually entered, we need to prevent + // the full screen mode. + if ( !this.isFullPage() ) { + return this; + } + + this.fullPageStyleWidth = this.element.style.width; + this.fullPageStyleHeight = this.element.style.height; + this.element.style.width = '100%'; + this.element.style.height = '100%'; + + var onFullScreenChange = function() { + var isFullScreen = $.isFullScreen(); + if ( !isFullScreen ) { + $.removeEvent( document, $.fullScreenEventName, onFullScreenChange ); + $.removeEvent( document, $.fullScreenErrorEventName, onFullScreenChange ); + + _this.setFullPage( false ); + if ( _this.isFullPage() ) { + _this.element.style.width = _this.fullPageStyleWidth; + _this.element.style.height = _this.fullPageStyleHeight; + } + } + if ( _this.navigator && _this.viewport ) { + _this.navigator.update( _this.viewport ); + } + /** + * Raised when the viewer has changed to/from full-screen mode (see {@link OpenSeadragon.Viewer#setFullScreen}). + * + * @event full-screen + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Boolean} fullScreen - True if changed to full-screen mode, false if exited full-screen mode. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( 'full-screen', { fullScreen: isFullScreen } ); + }; + $.addEvent( document, $.fullScreenEventName, onFullScreenChange ); + $.addEvent( document, $.fullScreenErrorEventName, onFullScreenChange ); + + $.requestFullScreen( document.body ); + + } else { + $.exitFullScreen(); + } + return this; + }, + + /** + * @function + * @return {Boolean} + */ + isVisible: function () { + return this.container.style.visibility != "hidden"; + }, + + + /** + * @function + * @param {Boolean} visible + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:visible + */ + setVisible: function( visible ){ + this.container.style.visibility = visible ? "" : "hidden"; + /** + * Raised when the viewer is shown or hidden (see {@link OpenSeadragon.Viewer#setVisible}). + * + * @event visible + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Boolean} visible + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'visible', { visible: visible } ); + return this; + }, + + /** + * Add a tiled image to the viewer. + * options.tileSource can be anything that {@link OpenSeadragon.Viewer#open} + * supports except arrays of images. + * Note that you can specify options.width or options.height, but not both. + * The other dimension will be calculated according to the item's aspect ratio. + * If collectionMode is on (see {@link OpenSeadragon.Options}), the new image is + * automatically arranged with the others. + * @function + * @param {Object} options + * @param {String|Object|Function} options.tileSource - The TileSource specifier. + * A String implies a url used to determine the tileSource implementation + * based on the file extension of url. JSONP is implied by *.js, + * otherwise the url is retrieved as text and the resulting text is + * introspected to determine if its json, xml, or text and parsed. + * An Object implies an inline configuration which has a single + * property sufficient for being able to determine tileSource + * implementation. If the object has a property which is a function + * named 'getTileUrl', it is treated as a custom TileSource. + * @param {Number} [options.index] The index of the item. Added on top of + * all other items if not specified. + * @param {Boolean} [options.replace=false] If true, the item at options.index will be + * removed and the new item is added in its place. options.tileSource will be + * interpreted and fetched if necessary before the old item is removed to avoid leaving + * a gap in the world. + * @param {Number} [options.x=0] The X position for the image in viewport coordinates. + * @param {Number} [options.y=0] The Y position for the image in viewport coordinates. + * @param {Number} [options.width=1] The width for the image in viewport coordinates. + * @param {Number} [options.height] The height for the image in viewport coordinates. + * @param {OpenSeadragon.Rect} [options.fitBounds] The bounds in viewport coordinates + * to fit the image into. If specified, x, y, width and height get ignored. + * @param {OpenSeadragon.Placement} [options.fitBoundsPlacement=OpenSeadragon.Placement.CENTER] + * How to anchor the image in the bounds if options.fitBounds is set. + * @param {OpenSeadragon.Rect} [options.clip] - An area, in image pixels, to clip to + * (portions of the image outside of this area will not be visible). Only works on + * browsers that support the HTML5 canvas. + * @param {Number} [options.opacity=1] Proportional opacity of the tiled images (1=opaque, 0=hidden) + * @param {Boolean} [options.preload=false] Default switch for loading hidden images (true loads, false blocks) + * @param {Number} [options.degrees=0] Initial rotation of the tiled image around + * its top left corner in degrees. + * @param {String} [options.compositeOperation] How the image is composited onto other images. + * @param {String} [options.crossOriginPolicy] The crossOriginPolicy for this specific image, + * overriding viewer.crossOriginPolicy. + * @param {Boolean} [options.ajaxWithCredentials] Whether to set withCredentials on tile AJAX + * @param {Boolean} [options.loadTilesWithAjax] + * Whether to load tile data using AJAX requests. + * Defaults to the setting in {@link OpenSeadragon.Options}. + * @param {Object} [options.ajaxHeaders] + * A set of headers to include when making tile AJAX requests. + * Note that these headers will be merged over any headers specified in {@link OpenSeadragon.Options}. + * Specifying a falsy value for a header will clear its existing value set at the Viewer level (if any). + * requests. + * @param {Function} [options.success] A function that gets called when the image is + * successfully added. It's passed the event object which contains a single property: + * "item", the resulting TiledImage. + * @param {Function} [options.error] A function that gets called if the image is + * unable to be added. It's passed the error event object, which contains "message" + * and "source" properties. + * @param {Boolean} [options.collectionImmediately=false] If collectionMode is on, + * specifies whether to snap to the new arrangement immediately or to animate to it. + * @param {String|CanvasGradient|CanvasPattern|Function} [options.placeholderFillStyle] - See {@link OpenSeadragon.Options}. + * @fires OpenSeadragon.World.event:add-item + * @fires OpenSeadragon.Viewer.event:add-item-failed + */ + addTiledImage: function( options ) { + $.console.assert(options, "[Viewer.addTiledImage] options is required"); + $.console.assert(options.tileSource, "[Viewer.addTiledImage] options.tileSource is required"); + $.console.assert(!options.replace || (options.index > -1 && options.index < this.world.getItemCount()), + "[Viewer.addTiledImage] if options.replace is used, options.index must be a valid index in Viewer.world"); + + var _this = this; + + if (options.replace) { + options.replaceItem = _this.world.getItemAt(options.index); + } + + this._hideMessage(); + + if (options.placeholderFillStyle === undefined) { + options.placeholderFillStyle = this.placeholderFillStyle; + } + if (options.opacity === undefined) { + options.opacity = this.opacity; + } + if (options.preload === undefined) { + options.preload = this.preload; + } + if (options.compositeOperation === undefined) { + options.compositeOperation = this.compositeOperation; + } + if (options.crossOriginPolicy === undefined) { + options.crossOriginPolicy = options.tileSource.crossOriginPolicy !== undefined ? options.tileSource.crossOriginPolicy : this.crossOriginPolicy; + } + if (options.ajaxWithCredentials === undefined) { + options.ajaxWithCredentials = this.ajaxWithCredentials; + } + if (options.loadTilesWithAjax === undefined) { + options.loadTilesWithAjax = this.loadTilesWithAjax; + } + if (options.ajaxHeaders === undefined || options.ajaxHeaders === null) { + options.ajaxHeaders = this.ajaxHeaders; + } else if ($.isPlainObject(options.ajaxHeaders) && $.isPlainObject(this.ajaxHeaders)) { + options.ajaxHeaders = $.extend({}, this.ajaxHeaders, options.ajaxHeaders); + } + + var myQueueItem = { + options: options + }; + + function raiseAddItemFailed( event ) { + for (var i = 0; i < _this._loadQueue.length; i++) { + if (_this._loadQueue[i] === myQueueItem) { + _this._loadQueue.splice(i, 1); + break; + } + } + + if (_this._loadQueue.length === 0) { + refreshWorld(myQueueItem); + } + + /** + * Raised when an error occurs while adding a item. + * @event add-item-failed + * @memberOf OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {String} message + * @property {String} source + * @property {Object} options The options passed to the addTiledImage method. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( 'add-item-failed', event ); + + if (options.error) { + options.error(event); + } + } + + function refreshWorld(theItem) { + if (_this.collectionMode) { + _this.world.arrange({ + immediately: theItem.options.collectionImmediately, + rows: _this.collectionRows, + columns: _this.collectionColumns, + layout: _this.collectionLayout, + tileSize: _this.collectionTileSize, + tileMargin: _this.collectionTileMargin + }); + _this.world.setAutoRefigureSizes(true); + } + } + + if ($.isArray(options.tileSource)) { + setTimeout(function() { + raiseAddItemFailed({ + message: "[Viewer.addTiledImage] Sequences can not be added; add them one at a time instead.", + source: options.tileSource, + options: options + }); + }); + return; + } + + this._loadQueue.push(myQueueItem); + + function processReadyItems() { + var queueItem, tiledImage, optionsClone; + while (_this._loadQueue.length) { + queueItem = _this._loadQueue[0]; + if (!queueItem.tileSource) { + break; + } + + _this._loadQueue.splice(0, 1); + + if (queueItem.options.replace) { + var newIndex = _this.world.getIndexOfItem(queueItem.options.replaceItem); + if (newIndex != -1) { + queueItem.options.index = newIndex; + } + _this.world.removeItem(queueItem.options.replaceItem); + } + + tiledImage = new $.TiledImage({ + viewer: _this, + source: queueItem.tileSource, + viewport: _this.viewport, + drawer: _this.drawer, + tileCache: _this.tileCache, + imageLoader: _this.imageLoader, + x: queueItem.options.x, + y: queueItem.options.y, + width: queueItem.options.width, + height: queueItem.options.height, + fitBounds: queueItem.options.fitBounds, + fitBoundsPlacement: queueItem.options.fitBoundsPlacement, + clip: queueItem.options.clip, + placeholderFillStyle: queueItem.options.placeholderFillStyle, + opacity: queueItem.options.opacity, + preload: queueItem.options.preload, + degrees: queueItem.options.degrees, + compositeOperation: queueItem.options.compositeOperation, + springStiffness: _this.springStiffness, + animationTime: _this.animationTime, + minZoomImageRatio: _this.minZoomImageRatio, + wrapHorizontal: _this.wrapHorizontal, + wrapVertical: _this.wrapVertical, + immediateRender: _this.immediateRender, + blendTime: _this.blendTime, + alwaysBlend: _this.alwaysBlend, + minPixelRatio: _this.minPixelRatio, + smoothTileEdgesMinZoom: _this.smoothTileEdgesMinZoom, + iOSDevice: _this.iOSDevice, + crossOriginPolicy: queueItem.options.crossOriginPolicy, + ajaxWithCredentials: queueItem.options.ajaxWithCredentials, + loadTilesWithAjax: queueItem.options.loadTilesWithAjax, + ajaxHeaders: queueItem.options.ajaxHeaders, + debugMode: _this.debugMode + }); + + if (_this.collectionMode) { + _this.world.setAutoRefigureSizes(false); + } + _this.world.addItem( tiledImage, { + index: queueItem.options.index + }); + + if (_this._loadQueue.length === 0) { + //this restores the autoRefigureSizes flag to true. + refreshWorld(queueItem); + } + + if (_this.world.getItemCount() === 1 && !_this.preserveViewport) { + _this.viewport.goHome(true); + } + + if (_this.navigator) { + optionsClone = $.extend({}, queueItem.options, { + replace: false, // navigator already removed the layer, nothing to replace + originalTiledImage: tiledImage, + tileSource: queueItem.tileSource + }); + + _this.navigator.addTiledImage(optionsClone); + } + + if (queueItem.options.success) { + queueItem.options.success({ + item: tiledImage + }); + } + } + } + + getTileSourceImplementation( this, options.tileSource, options, function( tileSource ) { + + myQueueItem.tileSource = tileSource; + + // add everybody at the front of the queue that's ready to go + processReadyItems(); + }, function( event ) { + event.options = options; + raiseAddItemFailed(event); + + // add everybody at the front of the queue that's ready to go + processReadyItems(); + } ); + }, + + /** + * Add a simple image to the viewer. + * The options are the same as the ones in {@link OpenSeadragon.Viewer#addTiledImage} + * except for options.tileSource which is replaced by options.url. + * @function + * @param {Object} options - See {@link OpenSeadragon.Viewer#addTiledImage} + * for all the options + * @param {String} options.url - The URL of the image to add. + * @fires OpenSeadragon.World.event:add-item + * @fires OpenSeadragon.Viewer.event:add-item-failed + */ + addSimpleImage: function(options) { + $.console.assert(options, "[Viewer.addSimpleImage] options is required"); + $.console.assert(options.url, "[Viewer.addSimpleImage] options.url is required"); + + var opts = $.extend({}, options, { + tileSource: { + type: 'image', + url: options.url + } + }); + delete opts.url; + this.addTiledImage(opts); + }, + + // deprecated + addLayer: function( options ) { + var _this = this; + + $.console.error( "[Viewer.addLayer] this function is deprecated; use Viewer.addTiledImage() instead." ); + + var optionsClone = $.extend({}, options, { + success: function(event) { + _this.raiseEvent("add-layer", { + options: options, + drawer: event.item + }); + }, + error: function(event) { + _this.raiseEvent("add-layer-failed", event); + } + }); + + this.addTiledImage(optionsClone); + return this; + }, + + // deprecated + getLayerAtLevel: function( level ) { + $.console.error( "[Viewer.getLayerAtLevel] this function is deprecated; use World.getItemAt() instead." ); + return this.world.getItemAt(level); + }, + + // deprecated + getLevelOfLayer: function( drawer ) { + $.console.error( "[Viewer.getLevelOfLayer] this function is deprecated; use World.getIndexOfItem() instead." ); + return this.world.getIndexOfItem(drawer); + }, + + // deprecated + getLayersCount: function() { + $.console.error( "[Viewer.getLayersCount] this function is deprecated; use World.getItemCount() instead." ); + return this.world.getItemCount(); + }, + + // deprecated + setLayerLevel: function( drawer, level ) { + $.console.error( "[Viewer.setLayerLevel] this function is deprecated; use World.setItemIndex() instead." ); + return this.world.setItemIndex(drawer, level); + }, + + // deprecated + removeLayer: function( drawer ) { + $.console.error( "[Viewer.removeLayer] this function is deprecated; use World.removeItem() instead." ); + return this.world.removeItem(drawer); + }, + + /** + * Force the viewer to redraw its contents. + * @returns {OpenSeadragon.Viewer} Chainable. + */ + forceRedraw: function() { + THIS[ this.hash ].forceRedraw = true; + return this; + }, + + /** + * @function + * @return {OpenSeadragon.Viewer} Chainable. + */ + bindSequenceControls: function(){ + + ////////////////////////////////////////////////////////////////////////// + // Image Sequence Controls + ////////////////////////////////////////////////////////////////////////// + var onFocusHandler = $.delegate( this, onFocus ), + onBlurHandler = $.delegate( this, onBlur ), + onNextHandler = $.delegate( this, onNext ), + onPreviousHandler = $.delegate( this, onPrevious ), + navImages = this.navImages, + useGroup = true; + + if( this.showSequenceControl ){ + + if( this.previousButton || this.nextButton ){ + //if we are binding to custom buttons then layout and + //grouping is the responsibility of the page author + useGroup = false; + } + + this.previousButton = new $.Button({ + element: this.previousButton ? $.getElement( this.previousButton ) : null, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + tooltip: $.getString( "Tooltips.PreviousPage" ), + srcRest: resolveUrl( this.prefixUrl, navImages.previous.REST ), + srcGroup: resolveUrl( this.prefixUrl, navImages.previous.GROUP ), + srcHover: resolveUrl( this.prefixUrl, navImages.previous.HOVER ), + srcDown: resolveUrl( this.prefixUrl, navImages.previous.DOWN ), + onRelease: onPreviousHandler, + onFocus: onFocusHandler, + onBlur: onBlurHandler + }); + + this.nextButton = new $.Button({ + element: this.nextButton ? $.getElement( this.nextButton ) : null, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + tooltip: $.getString( "Tooltips.NextPage" ), + srcRest: resolveUrl( this.prefixUrl, navImages.next.REST ), + srcGroup: resolveUrl( this.prefixUrl, navImages.next.GROUP ), + srcHover: resolveUrl( this.prefixUrl, navImages.next.HOVER ), + srcDown: resolveUrl( this.prefixUrl, navImages.next.DOWN ), + onRelease: onNextHandler, + onFocus: onFocusHandler, + onBlur: onBlurHandler + }); + + if( !this.navPrevNextWrap ){ + this.previousButton.disable(); + } + + if (!this.tileSources || !this.tileSources.length) { + this.nextButton.disable(); + } + + if( useGroup ){ + this.paging = new $.ButtonGroup({ + buttons: [ + this.previousButton, + this.nextButton + ], + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold + }); + + this.pagingControl = this.paging.element; + + if( this.toolbar ){ + this.toolbar.addControl( + this.pagingControl, + {anchor: $.ControlAnchor.BOTTOM_RIGHT} + ); + }else{ + this.addControl( + this.pagingControl, + {anchor: this.sequenceControlAnchor || $.ControlAnchor.TOP_LEFT} + ); + } + } + } + return this; + }, + + + /** + * @function + * @return {OpenSeadragon.Viewer} Chainable. + */ + bindStandardControls: function(){ + ////////////////////////////////////////////////////////////////////////// + // Navigation Controls + ////////////////////////////////////////////////////////////////////////// + var beginZoomingInHandler = $.delegate( this, beginZoomingIn ), + endZoomingHandler = $.delegate( this, endZooming ), + doSingleZoomInHandler = $.delegate( this, doSingleZoomIn ), + beginZoomingOutHandler = $.delegate( this, beginZoomingOut ), + doSingleZoomOutHandler = $.delegate( this, doSingleZoomOut ), + onHomeHandler = $.delegate( this, onHome ), + onFullScreenHandler = $.delegate( this, onFullScreen ), + onRotateLeftHandler = $.delegate( this, onRotateLeft ), + onRotateRightHandler = $.delegate( this, onRotateRight ), + onFocusHandler = $.delegate( this, onFocus ), + onBlurHandler = $.delegate( this, onBlur ), + navImages = this.navImages, + buttons = [], + useGroup = true; + + + if ( this.showNavigationControl ) { + + if( this.zoomInButton || this.zoomOutButton || + this.homeButton || this.fullPageButton || + this.rotateLeftButton || this.rotateRightButton ) { + //if we are binding to custom buttons then layout and + //grouping is the responsibility of the page author + useGroup = false; + } + + if ( this.showZoomControl ) { + buttons.push( this.zoomInButton = new $.Button({ + element: this.zoomInButton ? $.getElement( this.zoomInButton ) : null, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + tooltip: $.getString( "Tooltips.ZoomIn" ), + srcRest: resolveUrl( this.prefixUrl, navImages.zoomIn.REST ), + srcGroup: resolveUrl( this.prefixUrl, navImages.zoomIn.GROUP ), + srcHover: resolveUrl( this.prefixUrl, navImages.zoomIn.HOVER ), + srcDown: resolveUrl( this.prefixUrl, navImages.zoomIn.DOWN ), + onPress: beginZoomingInHandler, + onRelease: endZoomingHandler, + onClick: doSingleZoomInHandler, + onEnter: beginZoomingInHandler, + onExit: endZoomingHandler, + onFocus: onFocusHandler, + onBlur: onBlurHandler + })); + + buttons.push( this.zoomOutButton = new $.Button({ + element: this.zoomOutButton ? $.getElement( this.zoomOutButton ) : null, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + tooltip: $.getString( "Tooltips.ZoomOut" ), + srcRest: resolveUrl( this.prefixUrl, navImages.zoomOut.REST ), + srcGroup: resolveUrl( this.prefixUrl, navImages.zoomOut.GROUP ), + srcHover: resolveUrl( this.prefixUrl, navImages.zoomOut.HOVER ), + srcDown: resolveUrl( this.prefixUrl, navImages.zoomOut.DOWN ), + onPress: beginZoomingOutHandler, + onRelease: endZoomingHandler, + onClick: doSingleZoomOutHandler, + onEnter: beginZoomingOutHandler, + onExit: endZoomingHandler, + onFocus: onFocusHandler, + onBlur: onBlurHandler + })); + } + + if ( this.showHomeControl ) { + buttons.push( this.homeButton = new $.Button({ + element: this.homeButton ? $.getElement( this.homeButton ) : null, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + tooltip: $.getString( "Tooltips.Home" ), + srcRest: resolveUrl( this.prefixUrl, navImages.home.REST ), + srcGroup: resolveUrl( this.prefixUrl, navImages.home.GROUP ), + srcHover: resolveUrl( this.prefixUrl, navImages.home.HOVER ), + srcDown: resolveUrl( this.prefixUrl, navImages.home.DOWN ), + onRelease: onHomeHandler, + onFocus: onFocusHandler, + onBlur: onBlurHandler + })); + } + + if ( this.showFullPageControl ) { + buttons.push( this.fullPageButton = new $.Button({ + element: this.fullPageButton ? $.getElement( this.fullPageButton ) : null, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + tooltip: $.getString( "Tooltips.FullPage" ), + srcRest: resolveUrl( this.prefixUrl, navImages.fullpage.REST ), + srcGroup: resolveUrl( this.prefixUrl, navImages.fullpage.GROUP ), + srcHover: resolveUrl( this.prefixUrl, navImages.fullpage.HOVER ), + srcDown: resolveUrl( this.prefixUrl, navImages.fullpage.DOWN ), + onRelease: onFullScreenHandler, + onFocus: onFocusHandler, + onBlur: onBlurHandler + })); + } + + if ( this.showRotationControl ) { + buttons.push( this.rotateLeftButton = new $.Button({ + element: this.rotateLeftButton ? $.getElement( this.rotateLeftButton ) : null, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + tooltip: $.getString( "Tooltips.RotateLeft" ), + srcRest: resolveUrl( this.prefixUrl, navImages.rotateleft.REST ), + srcGroup: resolveUrl( this.prefixUrl, navImages.rotateleft.GROUP ), + srcHover: resolveUrl( this.prefixUrl, navImages.rotateleft.HOVER ), + srcDown: resolveUrl( this.prefixUrl, navImages.rotateleft.DOWN ), + onRelease: onRotateLeftHandler, + onFocus: onFocusHandler, + onBlur: onBlurHandler + })); + + buttons.push( this.rotateRightButton = new $.Button({ + element: this.rotateRightButton ? $.getElement( this.rotateRightButton ) : null, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + tooltip: $.getString( "Tooltips.RotateRight" ), + srcRest: resolveUrl( this.prefixUrl, navImages.rotateright.REST ), + srcGroup: resolveUrl( this.prefixUrl, navImages.rotateright.GROUP ), + srcHover: resolveUrl( this.prefixUrl, navImages.rotateright.HOVER ), + srcDown: resolveUrl( this.prefixUrl, navImages.rotateright.DOWN ), + onRelease: onRotateRightHandler, + onFocus: onFocusHandler, + onBlur: onBlurHandler + })); + + } + + if ( useGroup ) { + this.buttons = new $.ButtonGroup({ + buttons: buttons, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold + }); + + this.navControl = this.buttons.element; + this.addHandler( 'open', $.delegate( this, lightUp ) ); + + if( this.toolbar ){ + this.toolbar.addControl( + this.navControl, + {anchor: this.navigationControlAnchor || $.ControlAnchor.TOP_LEFT} + ); + } else { + this.addControl( + this.navControl, + {anchor: this.navigationControlAnchor || $.ControlAnchor.TOP_LEFT} + ); + } + } + + } + return this; + }, + + /** + * Gets the active page of a sequence + * @function + * @return {Number} + */ + currentPage: function() { + return this._sequenceIndex; + }, + + /** + * @function + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:page + */ + goToPage: function( page ){ + if( this.tileSources && page >= 0 && page < this.tileSources.length ){ + /** + * Raised when the page is changed on a viewer configured with multiple image sources (see {@link OpenSeadragon.Viewer#goToPage}). + * + * @event page + * @memberof OpenSeadragon.Viewer + * @type {Object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Number} page - The page index. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'page', { page: page } ); + + this._sequenceIndex = page; + + this._updateSequenceButtons( page ); + + this.open( this.tileSources[ page ] ); + + if( this.referenceStrip ){ + this.referenceStrip.setFocus( page ); + } + } + + return this; + }, + + /** + * Adds an html element as an overlay to the current viewport. Useful for + * highlighting words or areas of interest on an image or other zoomable + * interface. The overlays added via this method are removed when the viewport + * is closed which include when changing page. + * @method + * @param {Element|String|Object} element - A reference to an element or an id for + * the element which will be overlayed. Or an Object specifying the configuration for the overlay. + * If using an object, see {@link OpenSeadragon.Overlay} for a list of + * all available options. + * @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or + * rectangle which will be overlayed. This is a viewport relative location. + * @param {OpenSeadragon.Placement} placement - The position of the + * viewport which the location coordinates will be treated as relative + * to. + * @param {function} onDraw - If supplied the callback is called when the overlay + * needs to be drawn. It it the responsibility of the callback to do any drawing/positioning. + * It is passed position, size and element. + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:add-overlay + */ + addOverlay: function( element, location, placement, onDraw ) { + var options; + if( $.isPlainObject( element ) ){ + options = element; + } else { + options = { + element: element, + location: location, + placement: placement, + onDraw: onDraw + }; + } + + element = $.getElement( options.element ); + + if ( getOverlayIndex( this.currentOverlays, element ) >= 0 ) { + // they're trying to add a duplicate overlay + return this; + } + + var overlay = getOverlayObject( this, options); + this.currentOverlays.push(overlay); + overlay.drawHTML( this.overlaysContainer, this.viewport ); + + /** + * Raised when an overlay is added to the viewer (see {@link OpenSeadragon.Viewer#addOverlay}). + * + * @event add-overlay + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Element} element - The overlay element. + * @property {OpenSeadragon.Point|OpenSeadragon.Rect} location + * @property {OpenSeadragon.Placement} placement + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'add-overlay', { + element: element, + location: options.location, + placement: options.placement + }); + return this; + }, + + /** + * Updates the overlay represented by the reference to the element or + * element id moving it to the new location, relative to the new placement. + * @method + * @param {Element|String} element - A reference to an element or an id for + * the element which is overlayed. + * @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or + * rectangle which will be overlayed. This is a viewport relative location. + * @param {OpenSeadragon.Placement} placement - The position of the + * viewport which the location coordinates will be treated as relative + * to. + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:update-overlay + */ + updateOverlay: function( element, location, placement ) { + var i; + + element = $.getElement( element ); + i = getOverlayIndex( this.currentOverlays, element ); + + if ( i >= 0 ) { + this.currentOverlays[ i ].update( location, placement ); + THIS[ this.hash ].forceRedraw = true; + /** + * Raised when an overlay's location or placement changes + * (see {@link OpenSeadragon.Viewer#updateOverlay}). + * + * @event update-overlay + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the + * Viewer which raised the event. + * @property {Element} element + * @property {OpenSeadragon.Point|OpenSeadragon.Rect} location + * @property {OpenSeadragon.Placement} placement + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'update-overlay', { + element: element, + location: location, + placement: placement + }); + } + return this; + }, + + /** + * Removes an overlay identified by the reference element or element id + * and schedules an update. + * @method + * @param {Element|String} element - A reference to the element or an + * element id which represent the ovelay content to be removed. + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:remove-overlay + */ + removeOverlay: function( element ) { + var i; + + element = $.getElement( element ); + i = getOverlayIndex( this.currentOverlays, element ); + + if ( i >= 0 ) { + this.currentOverlays[ i ].destroy(); + this.currentOverlays.splice( i, 1 ); + THIS[ this.hash ].forceRedraw = true; + /** + * Raised when an overlay is removed from the viewer + * (see {@link OpenSeadragon.Viewer#removeOverlay}). + * + * @event remove-overlay + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the + * Viewer which raised the event. + * @property {Element} element - The overlay element. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'remove-overlay', { + element: element + }); + } + return this; + }, + + /** + * Removes all currently configured Overlays from this Viewer and schedules + * an update. + * @method + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:clear-overlay + */ + clearOverlays: function() { + while ( this.currentOverlays.length > 0 ) { + this.currentOverlays.pop().destroy(); + } + THIS[ this.hash ].forceRedraw = true; + /** + * Raised when all overlays are removed from the viewer (see {@link OpenSeadragon.Drawer#clearOverlays}). + * + * @event clear-overlay + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'clear-overlay', {} ); + return this; + }, + + /** + * Finds an overlay identified by the reference element or element id + * and returns it as an object, return null if not found. + * @method + * @param {Element|String} element - A reference to the element or an + * element id which represents the overlay content. + * @return {OpenSeadragon.Overlay} the matching overlay or null if none found. + */ + getOverlayById: function( element ) { + var i; + + element = $.getElement( element ); + i = getOverlayIndex( this.currentOverlays, element ); + + if (i >= 0) { + return this.currentOverlays[i]; + } else { + return null; + } + }, + + /** + * Updates the sequence buttons. + * @function OpenSeadragon.Viewer.prototype._updateSequenceButtons + * @private + * @param {Number} Sequence Value + */ + _updateSequenceButtons: function( page ) { + + if ( this.nextButton ) { + if(!this.tileSources || this.tileSources.length - 1 === page) { + //Disable next button + if ( !this.navPrevNextWrap ) { + this.nextButton.disable(); + } + } else { + this.nextButton.enable(); + } + } + if ( this.previousButton ) { + if ( page > 0 ) { + //Enable previous button + this.previousButton.enable(); + } else { + if ( !this.navPrevNextWrap ) { + this.previousButton.disable(); + } + } + } + }, + + /** + * Display a message in the viewport + * @function OpenSeadragon.Viewer.prototype._showMessage + * @private + * @param {String} text message + */ + _showMessage: function ( message ) { + this._hideMessage(); + + var div = $.makeNeutralElement( "div" ); + div.appendChild( document.createTextNode( message ) ); + + this.messageDiv = $.makeCenteredNode( div ); + + $.addClass(this.messageDiv, "openseadragon-message"); + + this.container.appendChild( this.messageDiv ); + }, + + /** + * Hide any currently displayed viewport message + * @function OpenSeadragon.Viewer.prototype._hideMessage + * @private + */ + _hideMessage: function () { + var div = this.messageDiv; + if (div) { + div.parentNode.removeChild(div); + delete this.messageDiv; + } + }, + + /** + * Gets this viewer's gesture settings for the given pointer device type. + * @method + * @param {String} type - The pointer device type to get the gesture settings for ("mouse", "touch", "pen", etc.). + * @return {OpenSeadragon.GestureSettings} + */ + gestureSettingsByDeviceType: function ( type ) { + switch ( type ) { + case 'mouse': + return this.gestureSettingsMouse; + case 'touch': + return this.gestureSettingsTouch; + case 'pen': + return this.gestureSettingsPen; + default: + return this.gestureSettingsUnknown; + } + }, + + // private + _drawOverlays: function() { + var i, + length = this.currentOverlays.length; + for ( i = 0; i < length; i++ ) { + this.currentOverlays[ i ].drawHTML( this.overlaysContainer, this.viewport ); + } + }, + + /** + * Cancel the "in flight" images. + */ + _cancelPendingImages: function() { + this._loadQueue = []; + }, + + /** + * Removes the reference strip and disables displaying it. + * @function + */ + removeReferenceStrip: function() { + this.showReferenceStrip = false; + + if (this.referenceStrip) { + this.referenceStrip.destroy(); + this.referenceStrip = null; + } + }, + + /** + * Enables and displays the reference strip based on the currently set tileSources. + * Works only when the Viewer has sequenceMode set to true. + * @function + */ + addReferenceStrip: function() { + this.showReferenceStrip = true; + + if (this.sequenceMode) { + if (this.referenceStrip) { + return; + } + + if (this.tileSources.length && this.tileSources.length > 1) { + this.referenceStrip = new $.ReferenceStrip({ + id: this.referenceStripElement, + position: this.referenceStripPosition, + sizeRatio: this.referenceStripSizeRatio, + scroll: this.referenceStripScroll, + height: this.referenceStripHeight, + width: this.referenceStripWidth, + tileSources: this.tileSources, + prefixUrl: this.prefixUrl, + viewer: this + }); + + this.referenceStrip.setFocus( this._sequenceIndex ); + } + } else { + $.console.warn('Attempting to display a reference strip while "sequenceMode" is off.'); + } + } +}); + + +/** + * _getSafeElemSize is like getElementSize(), but refuses to return 0 for x or y, + * which was causing some calling operations to return NaN. + * @returns {Point} + * @private + */ +function _getSafeElemSize (oElement) { + oElement = $.getElement( oElement ); + + return new $.Point( + (oElement.clientWidth === 0 ? 1 : oElement.clientWidth), + (oElement.clientHeight === 0 ? 1 : oElement.clientHeight) + ); +} + + +/** + * @function + * @private + */ +function getTileSourceImplementation( viewer, tileSource, imgOptions, successCallback, + failCallback ) { + var _this = viewer; + + //allow plain xml strings or json strings to be parsed here + if ( $.type( tileSource ) == 'string' ) { + //xml should start with "<" and end with ">" + if ( tileSource.match( /^\s*<.*>\s*$/ ) ) { + tileSource = $.parseXml( tileSource ); + //json should start with "{" or "[" and end with "}" or "]" + } else if ( tileSource.match(/^\s*[\{\[].*[\}\]]\s*$/ ) ) { + try { + var tileSourceJ = $.parseJSON(tileSource); + tileSource = tileSourceJ; + } catch (e) { + //tileSource = tileSource; + } + } + } + + function waitUntilReady(tileSource, originalTileSource) { + if (tileSource.ready) { + successCallback(tileSource); + } else { + tileSource.addHandler('ready', function () { + successCallback(tileSource); + }); + tileSource.addHandler('open-failed', function (event) { + failCallback({ + message: event.message, + source: originalTileSource + }); + }); + } + } + + setTimeout( function() { + if ( $.type( tileSource ) == 'string' ) { + //If its still a string it means it must be a url at this point + tileSource = new $.TileSource({ + url: tileSource, + crossOriginPolicy: imgOptions.crossOriginPolicy !== undefined ? + imgOptions.crossOriginPolicy : viewer.crossOriginPolicy, + ajaxWithCredentials: viewer.ajaxWithCredentials, + ajaxHeaders: viewer.ajaxHeaders, + useCanvas: viewer.useCanvas, + success: function( event ) { + successCallback( event.tileSource ); + } + }); + tileSource.addHandler( 'open-failed', function( event ) { + failCallback( event ); + } ); + + } else if ($.isPlainObject(tileSource) || tileSource.nodeType) { + if (tileSource.crossOriginPolicy === undefined && + (imgOptions.crossOriginPolicy !== undefined || viewer.crossOriginPolicy !== undefined)) { + tileSource.crossOriginPolicy = imgOptions.crossOriginPolicy !== undefined ? + imgOptions.crossOriginPolicy : viewer.crossOriginPolicy; + } + if (tileSource.ajaxWithCredentials === undefined) { + tileSource.ajaxWithCredentials = viewer.ajaxWithCredentials; + } + if (tileSource.useCanvas === undefined) { + tileSource.useCanvas = viewer.useCanvas; + } + + if ( $.isFunction( tileSource.getTileUrl ) ) { + //Custom tile source + var customTileSource = new $.TileSource( tileSource ); + customTileSource.getTileUrl = tileSource.getTileUrl; + successCallback( customTileSource ); + } else { + //inline configuration + var $TileSource = $.TileSource.determineType( _this, tileSource ); + if ( !$TileSource ) { + failCallback( { + message: "Unable to load TileSource", + source: tileSource + }); + return; + } + var options = $TileSource.prototype.configure.apply( _this, [ tileSource ] ); + waitUntilReady(new $TileSource(options), tileSource); + } + } else { + //can assume it's already a tile source implementation + waitUntilReady(tileSource, tileSource); + } + }); +} + +function getOverlayObject( viewer, overlay ) { + if ( overlay instanceof $.Overlay ) { + return overlay; + } + + var element = null; + if ( overlay.element ) { + element = $.getElement( overlay.element ); + } else { + var id = overlay.id ? + overlay.id : + "openseadragon-overlay-" + Math.floor( Math.random() * 10000000 ); + + element = $.getElement( overlay.id ); + if ( !element ) { + element = document.createElement( "a" ); + element.href = "#/overlay/" + id; + } + element.id = id; + $.addClass( element, overlay.className ? + overlay.className : + "openseadragon-overlay" + ); + } + + var location = overlay.location; + var width = overlay.width; + var height = overlay.height; + if (!location) { + var x = overlay.x; + var y = overlay.y; + if (overlay.px !== undefined) { + var rect = viewer.viewport.imageToViewportRectangle(new $.Rect( + overlay.px, + overlay.py, + width || 0, + height || 0)); + x = rect.x; + y = rect.y; + width = width !== undefined ? rect.width : undefined; + height = height !== undefined ? rect.height : undefined; + } + location = new $.Point(x, y); + } + + var placement = overlay.placement; + if (placement && $.type(placement) === "string") { + placement = $.Placement[overlay.placement.toUpperCase()]; + } + + return new $.Overlay({ + element: element, + location: location, + placement: placement, + onDraw: overlay.onDraw, + checkResize: overlay.checkResize, + width: width, + height: height, + rotationMode: overlay.rotationMode + }); +} + +/** + * @private + * @inner + * Determines the index of the given overlay in the given overlays array. + */ +function getOverlayIndex( overlays, element ) { + var i; + for ( i = overlays.length - 1; i >= 0; i-- ) { + if ( overlays[ i ].element === element ) { + return i; + } + } + + return -1; +} + +/////////////////////////////////////////////////////////////////////////////// +// Schedulers provide the general engine for animation +/////////////////////////////////////////////////////////////////////////////// +function scheduleUpdate( viewer, updateFunc ){ + return $.requestAnimationFrame( function(){ + updateFunc( viewer ); + } ); +} + + +//provides a sequence in the fade animation +function scheduleControlsFade( viewer ) { + $.requestAnimationFrame( function(){ + updateControlsFade( viewer ); + }); +} + + +//initiates an animation to hide the controls +function beginControlsAutoHide( viewer ) { + if ( !viewer.autoHideControls ) { + return; + } + viewer.controlsShouldFade = true; + viewer.controlsFadeBeginTime = + $.now() + + viewer.controlsFadeDelay; + + window.setTimeout( function(){ + scheduleControlsFade( viewer ); + }, viewer.controlsFadeDelay ); +} + + +//determines if fade animation is done or continues the animation +function updateControlsFade( viewer ) { + var currentTime, + deltaTime, + opacity, + i; + if ( viewer.controlsShouldFade ) { + currentTime = $.now(); + deltaTime = currentTime - viewer.controlsFadeBeginTime; + opacity = 1.0 - deltaTime / viewer.controlsFadeLength; + + opacity = Math.min( 1.0, opacity ); + opacity = Math.max( 0.0, opacity ); + + for ( i = viewer.controls.length - 1; i >= 0; i--) { + if (viewer.controls[ i ].autoFade) { + viewer.controls[ i ].setOpacity( opacity ); + } + } + + if ( opacity > 0 ) { + // fade again + scheduleControlsFade( viewer ); + } + } +} + + +//stop the fade animation on the controls and show them +function abortControlsAutoHide( viewer ) { + var i; + viewer.controlsShouldFade = false; + for ( i = viewer.controls.length - 1; i >= 0; i-- ) { + viewer.controls[ i ].setOpacity( 1.0 ); + } +} + + + +/////////////////////////////////////////////////////////////////////////////// +// Default view event handlers. +/////////////////////////////////////////////////////////////////////////////// +function onFocus(){ + abortControlsAutoHide( this ); +} + +function onBlur(){ + beginControlsAutoHide( this ); + +} + +function onCanvasKeyDown( event ) { + if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { + switch( event.keyCode ){ + case 38://up arrow + if ( event.shift ) { + this.viewport.zoomBy(1.1); + } else { + this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, -40))); + } + this.viewport.applyConstraints(); + return false; + case 40://down arrow + if ( event.shift ) { + this.viewport.zoomBy(0.9); + } else { + this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, 40))); + } + this.viewport.applyConstraints(); + return false; + case 37://left arrow + this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(-40, 0))); + this.viewport.applyConstraints(); + return false; + case 39://right arrow + this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(40, 0))); + this.viewport.applyConstraints(); + return false; + default: + //console.log( 'navigator keycode %s', event.keyCode ); + return true; + } + } else { + return true; + } +} + +function onCanvasKeyPress( event ) { + if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { + switch( event.keyCode ){ + case 43://=|+ + case 61://=|+ + this.viewport.zoomBy(1.1); + this.viewport.applyConstraints(); + return false; + case 45://-|_ + this.viewport.zoomBy(0.9); + this.viewport.applyConstraints(); + return false; + case 48://0|) + this.viewport.goHome(); + this.viewport.applyConstraints(); + return false; + case 119://w + case 87://W + if ( event.shift ) { + this.viewport.zoomBy(1.1); + } else { + this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, -40))); + } + this.viewport.applyConstraints(); + return false; + case 115://s + case 83://S + if ( event.shift ) { + this.viewport.zoomBy(0.9); + } else { + this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, 40))); + } + this.viewport.applyConstraints(); + return false; + case 97://a + this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(-40, 0))); + this.viewport.applyConstraints(); + return false; + case 100://d + this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(40, 0))); + this.viewport.applyConstraints(); + return false; + default: + //console.log( 'navigator keycode %s', event.keyCode ); + return true; + } + } else { + return true; + } +} + +function onCanvasClick( event ) { + var gestureSettings; + + var haveKeyboardFocus = document.activeElement == this.canvas; + + // If we don't have keyboard focus, request it. + if ( !haveKeyboardFocus ) { + this.canvas.focus(); + } + + var canvasClickEventArgs = { + tracker: event.eventSource, + position: event.position, + quick: event.quick, + shift: event.shift, + originalEvent: event.originalEvent, + preventDefaultAction: event.preventDefaultAction + }; + + /** + * Raised when a mouse press/release or touch/remove occurs on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-click + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Boolean} quick - True only if the clickDistThreshold and clickTimeThreshold are both passed. Useful for differentiating between clicks and drags. + * @property {Boolean} shift - True if the shift key was pressed during this event. + * @property {Object} originalEvent - The original DOM event. + * @property {Boolean} preventDefaultAction - Set to true to prevent default click to zoom behaviour. Default: false. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-click', canvasClickEventArgs); + + if ( !canvasClickEventArgs.preventDefaultAction && this.viewport && event.quick ) { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); + if ( gestureSettings.clickToZoom ) { + this.viewport.zoomBy( + event.shift ? 1.0 / this.zoomPerClick : this.zoomPerClick, + this.viewport.pointFromPixel( event.position, true ) + ); + this.viewport.applyConstraints(); + } + } +} + +function onCanvasDblClick( event ) { + var gestureSettings; + + if ( !event.preventDefaultAction && this.viewport ) { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); + if ( gestureSettings.dblClickToZoom ) { + this.viewport.zoomBy( + event.shift ? 1.0 / this.zoomPerClick : this.zoomPerClick, + this.viewport.pointFromPixel( event.position, true ) + ); + this.viewport.applyConstraints(); + } + } + /** + * Raised when a double mouse press/release or touch/remove occurs on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-double-click + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Boolean} shift - True if the shift key was pressed during this event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-double-click', { + tracker: event.eventSource, + position: event.position, + shift: event.shift, + originalEvent: event.originalEvent + }); +} + +function onCanvasDrag( event ) { + var gestureSettings; + + var canvasDragEventArgs = { + tracker: event.eventSource, + position: event.position, + delta: event.delta, + speed: event.speed, + direction: event.direction, + shift: event.shift, + originalEvent: event.originalEvent, + preventDefaultAction: event.preventDefaultAction + }; + + /** + * Raised when a mouse or touch drag operation occurs on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-drag + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {OpenSeadragon.Point} delta - The x,y components of the difference between start drag and end drag. + * @property {Number} speed - Current computed speed, in pixels per second. + * @property {Number} direction - Current computed direction, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0. + * @property {Boolean} shift - True if the shift key was pressed during this event. + * @property {Object} originalEvent - The original DOM event. + * @property {Boolean} preventDefaultAction - Set to true to prevent default drag behaviour. Default: false. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-drag', canvasDragEventArgs); + + if ( !canvasDragEventArgs.preventDefaultAction && this.viewport ) { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); + if( !this.panHorizontal ){ + event.delta.x = 0; + } + if( !this.panVertical ){ + event.delta.y = 0; + } + + if( this.constrainDuringPan ){ + var delta = this.viewport.deltaPointsFromPixels( event.delta.negate() ); + + this.viewport.centerSpringX.target.value += delta.x; + this.viewport.centerSpringY.target.value += delta.y; + + var bounds = this.viewport.getBounds(); + var constrainedBounds = this.viewport.getConstrainedBounds(); + + this.viewport.centerSpringX.target.value -= delta.x; + this.viewport.centerSpringY.target.value -= delta.y; + + if (bounds.x != constrainedBounds.x) { + event.delta.x = 0; + } + + if (bounds.y != constrainedBounds.y) { + event.delta.y = 0; + } + } + + this.viewport.panBy( this.viewport.deltaPointsFromPixels( event.delta.negate() ), gestureSettings.flickEnabled && !this.constrainDuringPan); + } +} + +function onCanvasDragEnd( event ) { + if (!event.preventDefaultAction && this.viewport) { + var gestureSettings = this.gestureSettingsByDeviceType(event.pointerType); + if (gestureSettings.flickEnabled && + event.speed >= gestureSettings.flickMinSpeed) { + var amplitudeX = 0; + if (this.panHorizontal) { + amplitudeX = gestureSettings.flickMomentum * event.speed * + Math.cos(event.direction); + } + var amplitudeY = 0; + if (this.panVertical) { + amplitudeY = gestureSettings.flickMomentum * event.speed * + Math.sin(event.direction); + } + var center = this.viewport.pixelFromPoint( + this.viewport.getCenter(true)); + var target = this.viewport.pointFromPixel( + new $.Point(center.x - amplitudeX, center.y - amplitudeY)); + this.viewport.panTo(target, false); + } + this.viewport.applyConstraints(); + } + /** + * Raised when a mouse or touch drag operation ends on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-drag-end + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} speed - Speed at the end of a drag gesture, in pixels per second. + * @property {Number} direction - Direction at the end of a drag gesture, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0. + * @property {Boolean} shift - True if the shift key was pressed during this event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('canvas-drag-end', { + tracker: event.eventSource, + position: event.position, + speed: event.speed, + direction: event.direction, + shift: event.shift, + originalEvent: event.originalEvent + }); +} + +function onCanvasEnter( event ) { + /** + * Raised when a pointer enters the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-enter + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {String} pointerType - "mouse", "touch", "pen", etc. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Number} pointers - Number of pointers (all types) active in the tracked element. + * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-enter', { + tracker: event.eventSource, + pointerType: event.pointerType, + position: event.position, + buttons: event.buttons, + pointers: event.pointers, + insideElementPressed: event.insideElementPressed, + buttonDownAny: event.buttonDownAny, + originalEvent: event.originalEvent + }); +} + +function onCanvasExit( event ) { + + if (window.location != window.parent.location){ + $.MouseTracker.resetAllMouseTrackers(); + } + + /** + * Raised when a pointer leaves the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-exit + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {String} pointerType - "mouse", "touch", "pen", etc. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Number} pointers - Number of pointers (all types) active in the tracked element. + * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-exit', { + tracker: event.eventSource, + pointerType: event.pointerType, + position: event.position, + buttons: event.buttons, + pointers: event.pointers, + insideElementPressed: event.insideElementPressed, + buttonDownAny: event.buttonDownAny, + originalEvent: event.originalEvent + }); +} + +function onCanvasPress( event ) { + /** + * Raised when the primary mouse button is pressed or touch starts on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-press + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {String} pointerType - "mouse", "touch", "pen", etc. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * @property {Boolean} insideElementReleased - True if the cursor still inside the tracked element when the button was released. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-press', { + tracker: event.eventSource, + pointerType: event.pointerType, + position: event.position, + insideElementPressed: event.insideElementPressed, + insideElementReleased: event.insideElementReleased, + originalEvent: event.originalEvent + }); +} + +function onCanvasRelease( event ) { + /** + * Raised when the primary mouse button is released or touch ends on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-release + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {String} pointerType - "mouse", "touch", "pen", etc. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * @property {Boolean} insideElementReleased - True if the cursor still inside the tracked element when the button was released. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-release', { + tracker: event.eventSource, + pointerType: event.pointerType, + position: event.position, + insideElementPressed: event.insideElementPressed, + insideElementReleased: event.insideElementReleased, + originalEvent: event.originalEvent + }); +} + +function onCanvasNonPrimaryPress( event ) { + /** + * Raised when any non-primary pointer button is pressed on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-nonprimary-press + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {String} pointerType - "mouse", "touch", "pen", etc. + * @property {Number} button - Button which caused the event. + * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. + * @property {Number} buttons - Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-nonprimary-press', { + tracker: event.eventSource, + position: event.position, + pointerType: event.pointerType, + button: event.button, + buttons: event.buttons, + originalEvent: event.originalEvent + }); +} + +function onCanvasNonPrimaryRelease( event ) { + /** + * Raised when any non-primary pointer button is released on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-nonprimary-release + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {String} pointerType - "mouse", "touch", "pen", etc. + * @property {Number} button - Button which caused the event. + * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. + * @property {Number} buttons - Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-nonprimary-release', { + tracker: event.eventSource, + position: event.position, + pointerType: event.pointerType, + button: event.button, + buttons: event.buttons, + originalEvent: event.originalEvent + }); +} + +function onCanvasPinch( event ) { + var gestureSettings, + centerPt, + lastCenterPt, + panByPt; + + if ( !event.preventDefaultAction && this.viewport ) { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); + if ( gestureSettings.pinchToZoom ) { + centerPt = this.viewport.pointFromPixel( event.center, true ); + lastCenterPt = this.viewport.pointFromPixel( event.lastCenter, true ); + panByPt = lastCenterPt.minus( centerPt ); + if( !this.panHorizontal ) { + panByPt.x = 0; + } + if( !this.panVertical ) { + panByPt.y = 0; + } + this.viewport.zoomBy( event.distance / event.lastDistance, centerPt, true ); + this.viewport.panBy( panByPt, true ); + this.viewport.applyConstraints(); + } + if ( gestureSettings.pinchRotate ) { + // Pinch rotate + var angle1 = Math.atan2(event.gesturePoints[0].currentPos.y - event.gesturePoints[1].currentPos.y, + event.gesturePoints[0].currentPos.x - event.gesturePoints[1].currentPos.x); + var angle2 = Math.atan2(event.gesturePoints[0].lastPos.y - event.gesturePoints[1].lastPos.y, + event.gesturePoints[0].lastPos.x - event.gesturePoints[1].lastPos.x); + this.viewport.setRotation(this.viewport.getRotation() + ((angle1 - angle2) * (180 / Math.PI))); + } + } + /** + * Raised when a pinch event occurs on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-pinch + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {Array.} gesturePoints - Gesture points associated with the gesture. Velocity data can be found here. + * @property {OpenSeadragon.Point} lastCenter - The previous center point of the two pinch contact points relative to the tracked element. + * @property {OpenSeadragon.Point} center - The center point of the two pinch contact points relative to the tracked element. + * @property {Number} lastDistance - The previous distance between the two pinch contact points in CSS pixels. + * @property {Number} distance - The distance between the two pinch contact points in CSS pixels. + * @property {Boolean} shift - True if the shift key was pressed during this event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('canvas-pinch', { + tracker: event.eventSource, + gesturePoints: event.gesturePoints, + lastCenter: event.lastCenter, + center: event.center, + lastDistance: event.lastDistance, + distance: event.distance, + shift: event.shift, + originalEvent: event.originalEvent + }); + //cancels event + return false; +} + +function onCanvasScroll( event ) { + var gestureSettings, + factor, + thisScrollTime, + deltaScrollTime; + + /* Certain scroll devices fire the scroll event way too fast so we are injecting a simple adjustment to keep things + * partially normalized. If we have already fired an event within the last 'minScrollDelta' milliseconds we skip + * this one and wait for the next event. */ + thisScrollTime = $.now(); + deltaScrollTime = thisScrollTime - this._lastScrollTime; + if (deltaScrollTime > this.minScrollDeltaTime) { + this._lastScrollTime = thisScrollTime; + + if ( !event.preventDefaultAction && this.viewport ) { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); + if ( gestureSettings.scrollToZoom ) { + factor = Math.pow( this.zoomPerScroll, event.scroll ); + this.viewport.zoomBy( + factor, + this.viewport.pointFromPixel( event.position, true ) + ); + this.viewport.applyConstraints(); + } + } + /** + * Raised when a scroll event occurs on the {@link OpenSeadragon.Viewer#canvas} element (mouse wheel). + * + * @event canvas-scroll + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} scroll - The scroll delta for the event. + * @property {Boolean} shift - True if the shift key was pressed during this event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-scroll', { + tracker: event.eventSource, + position: event.position, + scroll: event.scroll, + shift: event.shift, + originalEvent: event.originalEvent + }); + if (gestureSettings && gestureSettings.scrollToZoom) { + //cancels event + return false; + } + } + else { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); + if (gestureSettings && gestureSettings.scrollToZoom) { + return false; // We are swallowing this event + } + } +} + +function onContainerEnter( event ) { + THIS[ this.hash ].mouseInside = true; + abortControlsAutoHide( this ); + /** + * Raised when the cursor enters the {@link OpenSeadragon.Viewer#container} element. + * + * @event container-enter + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Number} pointers - Number of pointers (all types) active in the tracked element. + * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'container-enter', { + tracker: event.eventSource, + position: event.position, + buttons: event.buttons, + pointers: event.pointers, + insideElementPressed: event.insideElementPressed, + buttonDownAny: event.buttonDownAny, + originalEvent: event.originalEvent + }); +} + +function onContainerExit( event ) { + if ( event.pointers < 1 ) { + THIS[ this.hash ].mouseInside = false; + if ( !THIS[ this.hash ].animating ) { + beginControlsAutoHide( this ); + } + } + /** + * Raised when the cursor leaves the {@link OpenSeadragon.Viewer#container} element. + * + * @event container-exit + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Number} pointers - Number of pointers (all types) active in the tracked element. + * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'container-exit', { + tracker: event.eventSource, + position: event.position, + buttons: event.buttons, + pointers: event.pointers, + insideElementPressed: event.insideElementPressed, + buttonDownAny: event.buttonDownAny, + originalEvent: event.originalEvent + }); +} + + +/////////////////////////////////////////////////////////////////////////////// +// Page update routines ( aka Views - for future reference ) +/////////////////////////////////////////////////////////////////////////////// + +function updateMulti( viewer ) { + updateOnce( viewer ); + + // Request the next frame, unless we've been closed + if ( viewer.isOpen() ) { + viewer._updateRequestId = scheduleUpdate( viewer, updateMulti ); + } else { + viewer._updateRequestId = false; + } +} + +function updateOnce( viewer ) { + + //viewer.profiler.beginUpdate(); + + if (viewer._opening) { + return; + } + + if (viewer.autoResize) { + var containerSize = _getSafeElemSize(viewer.container); + var prevContainerSize = THIS[viewer.hash].prevContainerSize; + if (!containerSize.equals(prevContainerSize)) { + var viewport = viewer.viewport; + if (viewer.preserveImageSizeOnResize) { + var resizeRatio = prevContainerSize.x / containerSize.x; + var zoom = viewport.getZoom() * resizeRatio; + var center = viewport.getCenter(); + viewport.resize(containerSize, false); + viewport.zoomTo(zoom, null, true); + viewport.panTo(center, true); + } else { + // maintain image position + var oldBounds = viewport.getBounds(); + viewport.resize(containerSize, true); + viewport.fitBoundsWithConstraints(oldBounds, true); + } + THIS[viewer.hash].prevContainerSize = containerSize; + THIS[viewer.hash].forceRedraw = true; + } + } + + var viewportChange = viewer.viewport.update(); + var animated = viewer.world.update() || viewportChange; + + if (viewportChange) { + /** + * Raised when any spring animation update occurs (zoom, pan, etc.), + * before the viewer has drawn the new location. + * + * @event viewport-change + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + viewer.raiseEvent('viewport-change'); + } + + if( viewer.referenceStrip ){ + animated = viewer.referenceStrip.update( viewer.viewport ) || animated; + } + + if ( !THIS[ viewer.hash ].animating && animated ) { + /** + * Raised when any spring animation starts (zoom, pan, etc.). + * + * @event animation-start + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + viewer.raiseEvent( "animation-start" ); + abortControlsAutoHide( viewer ); + } + + if ( animated || THIS[ viewer.hash ].forceRedraw || viewer.world.needsDraw() ) { + drawWorld( viewer ); + viewer._drawOverlays(); + if( viewer.navigator ){ + viewer.navigator.update( viewer.viewport ); + } + + THIS[ viewer.hash ].forceRedraw = false; + + if (animated) { + /** + * Raised when any spring animation update occurs (zoom, pan, etc.), + * after the viewer has drawn the new location. + * + * @event animation + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + viewer.raiseEvent( "animation" ); + } + } + + if ( THIS[ viewer.hash ].animating && !animated ) { + /** + * Raised when any spring animation ends (zoom, pan, etc.). + * + * @event animation-finish + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + viewer.raiseEvent( "animation-finish" ); + + if ( !THIS[ viewer.hash ].mouseInside ) { + beginControlsAutoHide( viewer ); + } + } + + THIS[ viewer.hash ].animating = animated; + + //viewer.profiler.endUpdate(); +} + +function drawWorld( viewer ) { + viewer.imageLoader.clear(); + viewer.drawer.clear(); + viewer.world.draw(); + + /** + * - Needs documentation - + * + * @event update-viewport + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + viewer.raiseEvent( 'update-viewport', {} ); +} + +/////////////////////////////////////////////////////////////////////////////// +// Navigation Controls +/////////////////////////////////////////////////////////////////////////////// +function resolveUrl( prefix, url ) { + return prefix ? prefix + url : url; +} + + + +function beginZoomingIn() { + THIS[ this.hash ].lastZoomTime = $.now(); + THIS[ this.hash ].zoomFactor = this.zoomPerSecond; + THIS[ this.hash ].zooming = true; + scheduleZoom( this ); +} + + +function beginZoomingOut() { + THIS[ this.hash ].lastZoomTime = $.now(); + THIS[ this.hash ].zoomFactor = 1.0 / this.zoomPerSecond; + THIS[ this.hash ].zooming = true; + scheduleZoom( this ); +} + + +function endZooming() { + THIS[ this.hash ].zooming = false; +} + + +function scheduleZoom( viewer ) { + $.requestAnimationFrame( $.delegate( viewer, doZoom ) ); +} + + +function doZoom() { + var currentTime, + deltaTime, + adjustedFactor; + + if ( THIS[ this.hash ].zooming && this.viewport) { + currentTime = $.now(); + deltaTime = currentTime - THIS[ this.hash ].lastZoomTime; + adjustedFactor = Math.pow( THIS[ this.hash ].zoomFactor, deltaTime / 1000 ); + + this.viewport.zoomBy( adjustedFactor ); + this.viewport.applyConstraints(); + THIS[ this.hash ].lastZoomTime = currentTime; + scheduleZoom( this ); + } +} + + +function doSingleZoomIn() { + if ( this.viewport ) { + THIS[ this.hash ].zooming = false; + this.viewport.zoomBy( + this.zoomPerClick / 1.0 + ); + this.viewport.applyConstraints(); + } +} + + +function doSingleZoomOut() { + if ( this.viewport ) { + THIS[ this.hash ].zooming = false; + this.viewport.zoomBy( + 1.0 / this.zoomPerClick + ); + this.viewport.applyConstraints(); + } +} + + +function lightUp() { + this.buttons.emulateEnter(); + this.buttons.emulateExit(); +} + + +function onHome() { + if ( this.viewport ) { + this.viewport.goHome(); + } +} + + +function onFullScreen() { + if ( this.isFullPage() && !$.isFullScreen() ) { + // Is fullPage but not fullScreen + this.setFullPage( false ); + } else { + this.setFullScreen( !this.isFullPage() ); + } + // correct for no mouseout event on change + if ( this.buttons ) { + this.buttons.emulateExit(); + } + this.fullPageButton.element.focus(); + if ( this.viewport ) { + this.viewport.applyConstraints(); + } +} + +/** + * Note: The current rotation feature is limited to 90 degree turns. + */ +function onRotateLeft() { + if ( this.viewport ) { + var currRotation = this.viewport.getRotation(); + if (currRotation === 0) { + currRotation = 270; + } + else { + currRotation -= 90; + } + this.viewport.setRotation(currRotation); + } +} + +/** + * Note: The current rotation feature is limited to 90 degree turns. + */ +function onRotateRight() { + if ( this.viewport ) { + var currRotation = this.viewport.getRotation(); + if (currRotation === 270) { + currRotation = 0; + } + else { + currRotation += 90; + } + this.viewport.setRotation(currRotation); + } +} + + +function onPrevious(){ + var previous = this._sequenceIndex - 1; + if(this.navPrevNextWrap && previous < 0){ + previous += this.tileSources.length; + } + this.goToPage( previous ); +} + + +function onNext(){ + var next = this._sequenceIndex + 1; + if(this.navPrevNextWrap && next >= this.tileSources.length){ + next = 0; + } + this.goToPage( next ); +} + + +}( OpenSeadragon )); + +/* + * OpenSeadragon - Navigator + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class Navigator + * @classdesc The Navigator provides a small view of the current image as fixed + * while representing the viewport as a moving box serving as a frame + * of reference in the larger viewport as to which portion of the image + * is currently being examined. The navigator's viewport can be interacted + * with using the keyboard or the mouse. + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.Viewer + * @extends OpenSeadragon.EventSource + * @param {Object} options + */ +$.Navigator = function( options ){ + + var viewer = options.viewer, + _this = this, + viewerSize, + navigatorSize; + + //We may need to create a new element and id if they did not + //provide the id for the existing element + if( !options.id ){ + options.id = 'navigator-' + $.now(); + this.element = $.makeNeutralElement( "div" ); + options.controlOptions = { + anchor: $.ControlAnchor.TOP_RIGHT, + attachToViewer: true, + autoFade: options.autoFade + }; + + if( options.position ){ + if( 'BOTTOM_RIGHT' == options.position ){ + options.controlOptions.anchor = $.ControlAnchor.BOTTOM_RIGHT; + } else if( 'BOTTOM_LEFT' == options.position ){ + options.controlOptions.anchor = $.ControlAnchor.BOTTOM_LEFT; + } else if( 'TOP_RIGHT' == options.position ){ + options.controlOptions.anchor = $.ControlAnchor.TOP_RIGHT; + } else if( 'TOP_LEFT' == options.position ){ + options.controlOptions.anchor = $.ControlAnchor.TOP_LEFT; + } else if( 'ABSOLUTE' == options.position ){ + options.controlOptions.anchor = $.ControlAnchor.ABSOLUTE; + options.controlOptions.top = options.top; + options.controlOptions.left = options.left; + options.controlOptions.height = options.height; + options.controlOptions.width = options.width; + } + } + + } else { + this.element = document.getElementById( options.id ); + options.controlOptions = { + anchor: $.ControlAnchor.NONE, + attachToViewer: false, + autoFade: false + }; + } + this.element.id = options.id; + this.element.className += ' navigator'; + + options = $.extend( true, { + sizeRatio: $.DEFAULT_SETTINGS.navigatorSizeRatio + }, options, { + element: this.element, + tabIndex: -1, // No keyboard navigation, omit from tab order + //These need to be overridden to prevent recursion since + //the navigator is a viewer and a viewer has a navigator + showNavigator: false, + mouseNavEnabled: false, + showNavigationControl: false, + showSequenceControl: false, + immediateRender: true, + blendTime: 0, + animationTime: 0, + autoResize: options.autoResize, + // prevent resizing the navigator from adding unwanted space around the image + minZoomImageRatio: 1.0 + }); + + options.minPixelRatio = this.minPixelRatio = viewer.minPixelRatio; + + $.setElementTouchActionNone( this.element ); + + this.borderWidth = 2; + //At some browser magnification levels the display regions lines up correctly, but at some there appears to + //be a one pixel gap. + this.fudge = new $.Point(1, 1); + this.totalBorderWidths = new $.Point(this.borderWidth * 2, this.borderWidth * 2).minus(this.fudge); + + + if ( options.controlOptions.anchor != $.ControlAnchor.NONE ) { + (function( style, borderWidth ){ + style.margin = '0px'; + style.border = borderWidth + 'px solid #555'; + style.padding = '0px'; + style.background = '#000'; + style.opacity = 0.8; + style.overflow = 'hidden'; + }( this.element.style, this.borderWidth)); + } + + this.displayRegion = $.makeNeutralElement( "div" ); + this.displayRegion.id = this.element.id + '-displayregion'; + this.displayRegion.className = 'displayregion'; + + (function( style, borderWidth ){ + style.position = 'relative'; + style.top = '0px'; + style.left = '0px'; + style.fontSize = '0px'; + style.overflow = 'hidden'; + style.border = borderWidth + 'px solid #900'; + style.margin = '0px'; + style.padding = '0px'; + //TODO: IE doesnt like this property being set + //try{ style.outline = '2px auto #909'; }catch(e){/*ignore*/} + + style.background = 'transparent'; + + // We use square bracket notation on the statement below, because float is a keyword. + // This is important for the Google Closure compiler, if nothing else. + /*jshint sub:true */ + style['float'] = 'left'; //Webkit + + style.cssFloat = 'left'; //Firefox + style.styleFloat = 'left'; //IE + style.zIndex = 999999999; + style.cursor = 'default'; + }( this.displayRegion.style, this.borderWidth )); + + this.displayRegionContainer = $.makeNeutralElement("div"); + this.displayRegionContainer.id = this.element.id + '-displayregioncontainer'; + this.displayRegionContainer.className = "displayregioncontainer"; + this.displayRegionContainer.style.width = "100%"; + this.displayRegionContainer.style.height = "100%"; + + viewer.addControl( + this.element, + options.controlOptions + ); + + this._resizeWithViewer = options.controlOptions.anchor != $.ControlAnchor.ABSOLUTE && + options.controlOptions.anchor != $.ControlAnchor.NONE; + + if ( this._resizeWithViewer ) { + if ( options.width && options.height ) { + this.element.style.height = typeof (options.height) == "number" ? (options.height + 'px') : options.height; + this.element.style.width = typeof (options.width) == "number" ? (options.width + 'px') : options.width; + } else { + viewerSize = $.getElementSize( viewer.element ); + this.element.style.height = Math.round( viewerSize.y * options.sizeRatio ) + 'px'; + this.element.style.width = Math.round( viewerSize.x * options.sizeRatio ) + 'px'; + this.oldViewerSize = viewerSize; + } + navigatorSize = $.getElementSize( this.element ); + this.elementArea = navigatorSize.x * navigatorSize.y; + } + + this.oldContainerSize = new $.Point( 0, 0 ); + + $.Viewer.apply( this, [ options ] ); + + this.displayRegionContainer.appendChild(this.displayRegion); + this.element.getElementsByTagName('div')[0].appendChild(this.displayRegionContainer); + + function rotate(degrees) { + _setTransformRotate(_this.displayRegionContainer, degrees); + _setTransformRotate(_this.displayRegion, -degrees); + _this.viewport.setRotation(degrees); + } + if (options.navigatorRotate) { + var degrees = options.viewer.viewport ? + options.viewer.viewport.getRotation() : + options.viewer.degrees || 0; + rotate(degrees); + options.viewer.addHandler("rotate", function (args) { + rotate(args.degrees); + }); + } + + // Remove the base class' (Viewer's) innerTracker and replace it with our own + this.innerTracker.destroy(); + this.innerTracker = new $.MouseTracker({ + element: this.element, + dragHandler: $.delegate( this, onCanvasDrag ), + clickHandler: $.delegate( this, onCanvasClick ), + releaseHandler: $.delegate( this, onCanvasRelease ), + scrollHandler: $.delegate( this, onCanvasScroll ) + }); + + this.addHandler("reset-size", function() { + if (_this.viewport) { + _this.viewport.goHome(true); + } + }); + + viewer.world.addHandler("item-index-change", function(event) { + window.setTimeout(function(){ + var item = _this.world.getItemAt(event.previousIndex); + _this.world.setItemIndex(item, event.newIndex); + }, 1); + }); + + viewer.world.addHandler("remove-item", function(event) { + var theirItem = event.item; + var myItem = _this._getMatchingItem(theirItem); + if (myItem) { + _this.world.removeItem(myItem); + } + }); + + this.update(viewer.viewport); +}; + +$.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.Navigator.prototype */{ + + /** + * Used to notify the navigator when its size has changed. + * Especially useful when {@link OpenSeadragon.Options}.navigatorAutoResize is set to false and the navigator is resizable. + * @function + */ + updateSize: function () { + if ( this.viewport ) { + var containerSize = new $.Point( + (this.container.clientWidth === 0 ? 1 : this.container.clientWidth), + (this.container.clientHeight === 0 ? 1 : this.container.clientHeight) + ); + + if ( !containerSize.equals( this.oldContainerSize ) ) { + this.viewport.resize( containerSize, true ); + this.viewport.goHome(true); + this.oldContainerSize = containerSize; + this.drawer.clear(); + this.world.draw(); + } + } + }, + + /** + * Used to update the navigator minimap's viewport rectangle when a change in the viewer's viewport occurs. + * @function + * @param {OpenSeadragon.Viewport} The viewport this navigator is tracking. + */ + update: function( viewport ) { + + var viewerSize, + newWidth, + newHeight, + bounds, + topleft, + bottomright; + + viewerSize = $.getElementSize( this.viewer.element ); + if ( this._resizeWithViewer && viewerSize.x && viewerSize.y && !viewerSize.equals( this.oldViewerSize ) ) { + this.oldViewerSize = viewerSize; + + if ( this.maintainSizeRatio || !this.elementArea) { + newWidth = viewerSize.x * this.sizeRatio; + newHeight = viewerSize.y * this.sizeRatio; + } else { + newWidth = Math.sqrt(this.elementArea * (viewerSize.x / viewerSize.y)); + newHeight = this.elementArea / newWidth; + } + + this.element.style.width = Math.round( newWidth ) + 'px'; + this.element.style.height = Math.round( newHeight ) + 'px'; + + if (!this.elementArea) { + this.elementArea = newWidth * newHeight; + } + + this.updateSize(); + } + + if (viewport && this.viewport) { + bounds = viewport.getBoundsNoRotate(true); + topleft = this.viewport.pixelFromPointNoRotate(bounds.getTopLeft(), false); + bottomright = this.viewport.pixelFromPointNoRotate(bounds.getBottomRight(), false) + .minus( this.totalBorderWidths ); + + //update style for navigator-box + var style = this.displayRegion.style; + style.display = this.world.getItemCount() ? 'block' : 'none'; + + style.top = Math.round( topleft.y ) + 'px'; + style.left = Math.round( topleft.x ) + 'px'; + + var width = Math.abs( topleft.x - bottomright.x ); + var height = Math.abs( topleft.y - bottomright.y ); + // make sure width and height are non-negative so IE doesn't throw + style.width = Math.round( Math.max( width, 0 ) ) + 'px'; + style.height = Math.round( Math.max( height, 0 ) ) + 'px'; + } + + }, + + // overrides Viewer.addTiledImage + addTiledImage: function(options) { + var _this = this; + + var original = options.originalTiledImage; + delete options.original; + + var optionsClone = $.extend({}, options, { + success: function(event) { + var myItem = event.item; + myItem._originalForNavigator = original; + _this._matchBounds(myItem, original, true); + + function matchBounds() { + _this._matchBounds(myItem, original); + } + + function matchOpacity() { + _this._matchOpacity(myItem, original); + } + + function matchCompositeOperation() { + _this._matchCompositeOperation(myItem, original); + } + + original.addHandler('bounds-change', matchBounds); + original.addHandler('clip-change', matchBounds); + original.addHandler('opacity-change', matchOpacity); + original.addHandler('composite-operation-change', matchCompositeOperation); + } + }); + + return $.Viewer.prototype.addTiledImage.apply(this, [optionsClone]); + }, + + // private + _getMatchingItem: function(theirItem) { + var count = this.world.getItemCount(); + var item; + for (var i = 0; i < count; i++) { + item = this.world.getItemAt(i); + if (item._originalForNavigator === theirItem) { + return item; + } + } + + return null; + }, + + // private + _matchBounds: function(myItem, theirItem, immediately) { + var bounds = theirItem.getBoundsNoRotate(); + myItem.setPosition(bounds.getTopLeft(), immediately); + myItem.setWidth(bounds.width, immediately); + myItem.setRotation(theirItem.getRotation(), immediately); + myItem.setClip(theirItem.getClip()); + }, + + // private + _matchOpacity: function(myItem, theirItem) { + myItem.setOpacity(theirItem.opacity); + }, + + // private + _matchCompositeOperation: function(myItem, theirItem) { + myItem.setCompositeOperation(theirItem.compositeOperation); + } +}); + +/** + * @private + * @inner + * @function + */ +function onCanvasClick( event ) { + if ( event.quick && this.viewer.viewport ) { + this.viewer.viewport.panTo(this.viewport.pointFromPixel(event.position)); + this.viewer.viewport.applyConstraints(); + } +} + +/** + * @private + * @inner + * @function + */ +function onCanvasDrag( event ) { + if ( this.viewer.viewport ) { + if( !this.panHorizontal ){ + event.delta.x = 0; + } + if( !this.panVertical ){ + event.delta.y = 0; + } + this.viewer.viewport.panBy( + this.viewport.deltaPointsFromPixels( + event.delta + ) + ); + if( this.viewer.constrainDuringPan ){ + this.viewer.viewport.applyConstraints(); + } + } +} + + +/** + * @private + * @inner + * @function + */ +function onCanvasRelease( event ) { + if ( event.insideElementPressed && this.viewer.viewport ) { + this.viewer.viewport.applyConstraints(); + } +} + + +/** + * @private + * @inner + * @function + */ +function onCanvasScroll( event ) { + /** + * Raised when a scroll event occurs on the {@link OpenSeadragon.Viewer#navigator} element (mouse wheel, touch pinch, etc.). + * + * @event navigator-scroll + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} scroll - The scroll delta for the event. + * @property {Boolean} shift - True if the shift key was pressed during this event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.viewer.raiseEvent( 'navigator-scroll', { + tracker: event.eventSource, + position: event.position, + scroll: event.scroll, + shift: event.shift, + originalEvent: event.originalEvent + }); + + //dont scroll the page up and down if the user is scrolling + //in the navigator + return false; +} + +/** + * @function + * @private + * @param {Object} element + * @param {Number} degrees + */ +function _setTransformRotate (element, degrees) { + element.style.webkitTransform = "rotate(" + degrees + "deg)"; + element.style.mozTransform = "rotate(" + degrees + "deg)"; + element.style.msTransform = "rotate(" + degrees + "deg)"; + element.style.oTransform = "rotate(" + degrees + "deg)"; + element.style.transform = "rotate(" + degrees + "deg)"; +} + +}( OpenSeadragon )); + +/* + * OpenSeadragon - getString/setString + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +//TODO: I guess this is where the i18n needs to be reimplemented. I'll look +// into existing patterns for i18n in javascript but i think that mimicking +// pythons gettext might be a reasonable approach. +var I18N = { + Errors: { + Dzc: "Sorry, we don't support Deep Zoom Collections!", + Dzi: "Hmm, this doesn't appear to be a valid Deep Zoom Image.", + Xml: "Hmm, this doesn't appear to be a valid Deep Zoom Image.", + ImageFormat: "Sorry, we don't support {0}-based Deep Zoom Images.", + Security: "It looks like a security restriction stopped us from " + + "loading this Deep Zoom Image.", + Status: "This space unintentionally left blank ({0} {1}).", + OpenFailed: "Unable to open {0}: {1}" + }, + + Tooltips: { + FullPage: "Toggle full page", + Home: "Go home", + ZoomIn: "Zoom in", + ZoomOut: "Zoom out", + NextPage: "Next page", + PreviousPage: "Previous page", + RotateLeft: "Rotate left", + RotateRight: "Rotate right" + } +}; + +$.extend( $, /** @lends OpenSeadragon */{ + + /** + * @function + * @param {String} property + */ + getString: function( prop ) { + + var props = prop.split('.'), + string = null, + args = arguments, + container = I18N, + i; + + for (i = 0; i < props.length - 1; i++) { + // in case not a subproperty + container = container[ props[ i ] ] || {}; + } + string = container[ props[ i ] ]; + + if ( typeof( string ) != "string" ) { + $.console.log( "Untranslated source string:", prop ); + string = ""; // FIXME: this breaks gettext()-style convention, which would return source + } + + return string.replace(/\{\d+\}/g, function(capture) { + var i = parseInt( capture.match( /\d+/ ), 10 ) + 1; + return i < args.length ? + args[ i ] : + ""; + }); + }, + + /** + * @function + * @param {String} property + * @param {*} value + */ + setString: function( prop, value ) { + + var props = prop.split('.'), + container = I18N, + i; + + for ( i = 0; i < props.length - 1; i++ ) { + if ( !container[ props[ i ] ] ) { + container[ props[ i ] ] = {}; + } + container = container[ props[ i ] ]; + } + + container[ props[ i ] ] = value; + } + +}); + +}( OpenSeadragon )); + +/* + * OpenSeadragon - Point + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class Point + * @classdesc A Point is really used as a 2-dimensional vector, equally useful for + * representing a point on a plane, or the height and width of a plane + * not requiring any other frame of reference. + * + * @memberof OpenSeadragon + * @param {Number} [x] The vector component 'x'. Defaults to the origin at 0. + * @param {Number} [y] The vector component 'y'. Defaults to the origin at 0. + */ +$.Point = function( x, y ) { + /** + * The vector component 'x'. + * @member {Number} x + * @memberof OpenSeadragon.Point# + */ + this.x = typeof ( x ) == "number" ? x : 0; + /** + * The vector component 'y'. + * @member {Number} y + * @memberof OpenSeadragon.Point# + */ + this.y = typeof ( y ) == "number" ? y : 0; +}; + +/** @lends OpenSeadragon.Point.prototype */ +$.Point.prototype = { + /** + * @function + * @returns {OpenSeadragon.Point} a duplicate of this Point + */ + clone: function() { + return new $.Point(this.x, this.y); + }, + + /** + * Add another Point to this point and return a new Point. + * @function + * @param {OpenSeadragon.Point} point The point to add vector components. + * @returns {OpenSeadragon.Point} A new point representing the sum of the + * vector components + */ + plus: function( point ) { + return new $.Point( + this.x + point.x, + this.y + point.y + ); + }, + + /** + * Substract another Point to this point and return a new Point. + * @function + * @param {OpenSeadragon.Point} point The point to substract vector components. + * @returns {OpenSeadragon.Point} A new point representing the substraction of the + * vector components + */ + minus: function( point ) { + return new $.Point( + this.x - point.x, + this.y - point.y + ); + }, + + /** + * Multiply this point by a factor and return a new Point. + * @function + * @param {Number} factor The factor to multiply vector components. + * @returns {OpenSeadragon.Point} A new point representing the multiplication + * of the vector components by the factor + */ + times: function( factor ) { + return new $.Point( + this.x * factor, + this.y * factor + ); + }, + + /** + * Divide this point by a factor and return a new Point. + * @function + * @param {Number} factor The factor to divide vector components. + * @returns {OpenSeadragon.Point} A new point representing the division of the + * vector components by the factor + */ + divide: function( factor ) { + return new $.Point( + this.x / factor, + this.y / factor + ); + }, + + /** + * Compute the opposite of this point and return a new Point. + * @function + * @returns {OpenSeadragon.Point} A new point representing the opposite of the + * vector components + */ + negate: function() { + return new $.Point( -this.x, -this.y ); + }, + + /** + * Compute the distance between this point and another point. + * @function + * @param {OpenSeadragon.Point} point The point to compute the distance with. + * @returns {Number} The distance between the 2 points + */ + distanceTo: function( point ) { + return Math.sqrt( + Math.pow( this.x - point.x, 2 ) + + Math.pow( this.y - point.y, 2 ) + ); + }, + + /** + * Compute the squared distance between this point and another point. + * Useful for optimizing things like comparing distances. + * @function + * @param {OpenSeadragon.Point} point The point to compute the squared distance with. + * @returns {Number} The squared distance between the 2 points + */ + squaredDistanceTo: function( point ) { + return Math.pow( this.x - point.x, 2 ) + + Math.pow( this.y - point.y, 2 ); + }, + + /** + * Apply a function to each coordinate of this point and return a new point. + * @function + * @param {function} func The function to apply to each coordinate. + * @returns {OpenSeadragon.Point} A new point with the coordinates computed + * by the specified function + */ + apply: function( func ) { + return new $.Point( func( this.x ), func( this.y ) ); + }, + + /** + * Check if this point is equal to another one. + * @function + * @param {OpenSeadragon.Point} point The point to compare this point with. + * @returns {Boolean} true if they are equal, false otherwise. + */ + equals: function( point ) { + return ( + point instanceof $.Point + ) && ( + this.x === point.x + ) && ( + this.y === point.y + ); + }, + + /** + * Rotates the point around the specified pivot + * From http://stackoverflow.com/questions/4465931/rotate-rectangle-around-a-point + * @function + * @param {Number} degress to rotate around the pivot. + * @param {OpenSeadragon.Point} [pivot=(0,0)] Point around which to rotate. + * Defaults to the origin. + * @returns {OpenSeadragon.Point}. A new point representing the point rotated around the specified pivot + */ + rotate: function (degrees, pivot) { + pivot = pivot || new $.Point(0, 0); + var cos; + var sin; + // Avoid float computations when possible + if (degrees % 90 === 0) { + var d = $.positiveModulo(degrees, 360); + switch (d) { + case 0: + cos = 1; + sin = 0; + break; + case 90: + cos = 0; + sin = 1; + break; + case 180: + cos = -1; + sin = 0; + break; + case 270: + cos = 0; + sin = -1; + break; + } + } else { + var angle = degrees * Math.PI / 180.0; + cos = Math.cos(angle); + sin = Math.sin(angle); + } + var x = cos * (this.x - pivot.x) - sin * (this.y - pivot.y) + pivot.x; + var y = sin * (this.x - pivot.x) + cos * (this.y - pivot.y) + pivot.y; + return new $.Point(x, y); + }, + + /** + * Convert this point to a string in the format (x,y) where x and y are + * rounded to the nearest integer. + * @function + * @returns {String} A string representation of this point. + */ + toString: function() { + return "(" + (Math.round(this.x * 100) / 100) + "," + (Math.round(this.y * 100) / 100) + ")"; + } +}; + +}( OpenSeadragon )); + +/* + * OpenSeadragon - TileSource + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + + +/** + * @class TileSource + * @classdesc The TileSource contains the most basic implementation required to create a + * smooth transition between layers in an image pyramid. It has only a single key + * interface that must be implemented to complete its key functionality: + * 'getTileUrl'. It also has several optional interfaces that can be + * implemented if a new TileSource wishes to support configuration via a simple + * object or array ('configure') and if the tile source supports or requires + * configuration via retrieval of a document on the network ala AJAX or JSONP, + * ('getImageInfo'). + *
      + * By default the image pyramid is split into N layers where the image's longest + * side in M (in pixels), where N is the smallest integer which satisfies + * 2^(N+1) >= M. + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.EventSource + * @param {Object} options + * You can either specify a URL, or literally define the TileSource (by specifying + * width, height, tileSize, tileOverlap, minLevel, and maxLevel). For the former, + * the extending class is expected to implement 'getImageInfo' and 'configure'. + * For the latter, the construction is assumed to occur through + * the extending classes implementation of 'configure'. + * @param {String} [options.url] + * The URL for the data necessary for this TileSource. + * @param {String} [options.referenceStripThumbnailUrl] + * The URL for a thumbnail image to be used by the reference strip + * @param {Function} [options.success] + * A function to be called upon successful creation. + * @param {Boolean} [options.ajaxWithCredentials] + * If this TileSource needs to make an AJAX call, this specifies whether to set + * the XHR's withCredentials (for accessing secure data). + * @param {Object} [options.ajaxHeaders] + * A set of headers to include in AJAX requests. + * @param {Number} [options.width] + * Width of the source image at max resolution in pixels. + * @param {Number} [options.height] + * Height of the source image at max resolution in pixels. + * @param {Number} [options.tileSize] + * The size of the tiles to assumed to make up each pyramid layer in pixels. + * Tile size determines the point at which the image pyramid must be + * divided into a matrix of smaller images. + * Use options.tileWidth and options.tileHeight to support non-square tiles. + * @param {Number} [options.tileWidth] + * The width of the tiles to assumed to make up each pyramid layer in pixels. + * @param {Number} [options.tileHeight] + * The height of the tiles to assumed to make up each pyramid layer in pixels. + * @param {Number} [options.tileOverlap] + * The number of pixels each tile is expected to overlap touching tiles. + * @param {Number} [options.minLevel] + * The minimum level to attempt to load. + * @param {Number} [options.maxLevel] + * The maximum level to attempt to load. + */ +$.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLevel ) { + var _this = this; + + var args = arguments, + options, + i; + + if( $.isPlainObject( width ) ){ + options = width; + }else{ + options = { + width: args[0], + height: args[1], + tileSize: args[2], + tileOverlap: args[3], + minLevel: args[4], + maxLevel: args[5] + }; + } + + //Tile sources supply some events, namely 'ready' when they must be configured + //by asynchronously fetching their configuration data. + $.EventSource.call( this ); + + //we allow options to override anything we dont treat as + //required via idiomatic options or which is functionally + //set depending on the state of the readiness of this tile + //source + $.extend( true, this, options ); + + if (!this.success) { + //Any functions that are passed as arguments are bound to the ready callback + for ( i = 0; i < arguments.length; i++ ) { + if ( $.isFunction( arguments[ i ] ) ) { + this.success = arguments[ i ]; + //only one callback per constructor + break; + } + } + } + + if (this.success) { + this.addHandler( 'ready', function ( event ) { + _this.success( event ); + } ); + } + + /** + * Ratio of width to height + * @member {Number} aspectRatio + * @memberof OpenSeadragon.TileSource# + */ + /** + * Vector storing x and y dimensions ( width and height respectively ). + * @member {OpenSeadragon.Point} dimensions + * @memberof OpenSeadragon.TileSource# + */ + /** + * The overlap in pixels each tile shares with its adjacent neighbors. + * @member {Number} tileOverlap + * @memberof OpenSeadragon.TileSource# + */ + /** + * The minimum pyramid level this tile source supports or should attempt to load. + * @member {Number} minLevel + * @memberof OpenSeadragon.TileSource# + */ + /** + * The maximum pyramid level this tile source supports or should attempt to load. + * @member {Number} maxLevel + * @memberof OpenSeadragon.TileSource# + */ + /** + * + * @member {Boolean} ready + * @memberof OpenSeadragon.TileSource# + */ + + if( 'string' == $.type( arguments[ 0 ] ) ){ + this.url = arguments[0]; + } + + if (this.url) { + //in case the getImageInfo method is overriden and/or implies an + //async mechanism set some safe defaults first + this.aspectRatio = 1; + this.dimensions = new $.Point( 10, 10 ); + this._tileWidth = 0; + this._tileHeight = 0; + this.tileOverlap = 0; + this.minLevel = 0; + this.maxLevel = 0; + this.ready = false; + //configuration via url implies the extending class + //implements and 'configure' + this.getImageInfo( this.url ); + + } else { + + //explicit configuration via positional args in constructor + //or the more idiomatic 'options' object + this.ready = true; + this.aspectRatio = (options.width && options.height) ? + (options.width / options.height) : 1; + this.dimensions = new $.Point( options.width, options.height ); + + if ( this.tileSize ){ + this._tileWidth = this._tileHeight = this.tileSize; + delete this.tileSize; + } else { + if( this.tileWidth ){ + // We were passed tileWidth in options, but we want to rename it + // with a leading underscore to make clear that it is not safe to directly modify it + this._tileWidth = this.tileWidth; + delete this.tileWidth; + } else { + this._tileWidth = 0; + } + + if( this.tileHeight ){ + // See note above about renaming this.tileWidth + this._tileHeight = this.tileHeight; + delete this.tileHeight; + } else { + this._tileHeight = 0; + } + } + + this.tileOverlap = options.tileOverlap ? options.tileOverlap : 0; + this.minLevel = options.minLevel ? options.minLevel : 0; + this.maxLevel = ( undefined !== options.maxLevel && null !== options.maxLevel ) ? + options.maxLevel : ( + ( options.width && options.height ) ? Math.ceil( + Math.log( Math.max( options.width, options.height ) ) / + Math.log( 2 ) + ) : 0 + ); + if( this.success && $.isFunction( this.success ) ){ + this.success( this ); + } + } + + +}; + +/** @lends OpenSeadragon.TileSource.prototype */ +$.TileSource.prototype = { + + getTileSize: function( level ) { + $.console.error( + "[TileSource.getTileSize] is deprecated." + + "Use TileSource.getTileWidth() and TileSource.getTileHeight() instead" + ); + return this._tileWidth; + }, + + /** + * Return the tileWidth for a given level. + * Subclasses should override this if tileWidth can be different at different levels + * such as in IIIFTileSource. Code should use this function rather than reading + * from ._tileWidth directly. + * @function + * @param {Number} level + */ + getTileWidth: function( level ) { + if (!this._tileWidth) { + return this.getTileSize(level); + } + return this._tileWidth; + }, + + /** + * Return the tileHeight for a given level. + * Subclasses should override this if tileHeight can be different at different levels + * such as in IIIFTileSource. Code should use this function rather than reading + * from ._tileHeight directly. + * @function + * @param {Number} level + */ + getTileHeight: function( level ) { + if (!this._tileHeight) { + return this.getTileSize(level); + } + return this._tileHeight; + }, + + /** + * @function + * @param {Number} level + */ + getLevelScale: function( level ) { + + // see https://github.com/openseadragon/openseadragon/issues/22 + // we use the tilesources implementation of getLevelScale to generate + // a memoized re-implementation + var levelScaleCache = {}, + i; + for( i = 0; i <= this.maxLevel; i++ ){ + levelScaleCache[ i ] = 1 / Math.pow(2, this.maxLevel - i); + } + this.getLevelScale = function( _level ){ + return levelScaleCache[ _level ]; + }; + return this.getLevelScale( level ); + }, + + /** + * @function + * @param {Number} level + */ + getNumTiles: function( level ) { + var scale = this.getLevelScale( level ), + x = Math.ceil( scale * this.dimensions.x / this.getTileWidth(level) ), + y = Math.ceil( scale * this.dimensions.y / this.getTileHeight(level) ); + + return new $.Point( x, y ); + }, + + /** + * @function + * @param {Number} level + */ + getPixelRatio: function( level ) { + var imageSizeScaled = this.dimensions.times( this.getLevelScale( level ) ), + rx = 1.0 / imageSizeScaled.x, + ry = 1.0 / imageSizeScaled.y; + + return new $.Point(rx, ry); + }, + + + /** + * @function + * @returns {Number} The highest level in this tile source that can be contained in a single tile. + */ + getClosestLevel: function() { + var i, + tiles; + + for (i = this.minLevel + 1; i <= this.maxLevel; i++){ + tiles = this.getNumTiles(i); + if (tiles.x > 1 || tiles.y > 1) { + break; + } + } + + return i - 1; + }, + + /** + * @function + * @param {Number} level + * @param {OpenSeadragon.Point} point + */ + getTileAtPoint: function(level, point) { + var validPoint = point.x >= 0 && point.x <= 1 && + point.y >= 0 && point.y <= 1 / this.aspectRatio; + $.console.assert(validPoint, "[TileSource.getTileAtPoint] must be called with a valid point."); + + var widthScaled = this.dimensions.x * this.getLevelScale(level); + var pixelX = point.x * widthScaled; + var pixelY = point.y * widthScaled; + + var x = Math.floor(pixelX / this.getTileWidth(level)); + var y = Math.floor(pixelY / this.getTileHeight(level)); + + // When point.x == 1 or point.y == 1 / this.aspectRatio we want to + // return the last tile of the row/column + if (point.x >= 1) { + x = this.getNumTiles(level).x - 1; + } + var EPSILON = 1e-16; + if (point.y >= 1 / this.aspectRatio - EPSILON) { + y = this.getNumTiles(level).y - 1; + } + + return new $.Point(x, y); + }, + + /** + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + */ + getTileBounds: function( level, x, y ) { + var dimensionsScaled = this.dimensions.times( this.getLevelScale( level ) ), + tileWidth = this.getTileWidth(level), + tileHeight = this.getTileHeight(level), + px = ( x === 0 ) ? 0 : tileWidth * x - this.tileOverlap, + py = ( y === 0 ) ? 0 : tileHeight * y - this.tileOverlap, + sx = tileWidth + ( x === 0 ? 1 : 2 ) * this.tileOverlap, + sy = tileHeight + ( y === 0 ? 1 : 2 ) * this.tileOverlap, + scale = 1.0 / dimensionsScaled.x; + + sx = Math.min( sx, dimensionsScaled.x - px ); + sy = Math.min( sy, dimensionsScaled.y - py ); + + return new $.Rect( px * scale, py * scale, sx * scale, sy * scale ); + }, + + + /** + * Responsible for retrieving, and caching the + * image metadata pertinent to this TileSources implementation. + * @function + * @param {String} url + * @throws {Error} + */ + getImageInfo: function( url ) { + var _this = this, + callbackName, + callback, + readySource, + options, + urlParts, + filename, + lastDot; + + + if( url ) { + urlParts = url.split( '/' ); + filename = urlParts[ urlParts.length - 1 ]; + lastDot = filename.lastIndexOf( '.' ); + if ( lastDot > -1 ) { + urlParts[ urlParts.length - 1 ] = filename.slice( 0, lastDot ); + } + } + + callback = function( data ){ + if( typeof(data) === "string" ) { + data = $.parseXml( data ); + } + var $TileSource = $.TileSource.determineType( _this, data, url ); + if ( !$TileSource ) { + /** + * Raised when an error occurs loading a TileSource. + * + * @event open-failed + * @memberof OpenSeadragon.TileSource + * @type {object} + * @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event. + * @property {String} message + * @property {String} source + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( 'open-failed', { message: "Unable to load TileSource", source: url } ); + return; + } + + options = $TileSource.prototype.configure.apply( _this, [ data, url ]); + if (options.ajaxWithCredentials === undefined) { + options.ajaxWithCredentials = _this.ajaxWithCredentials; + } + + readySource = new $TileSource( options ); + _this.ready = true; + /** + * Raised when a TileSource is opened and initialized. + * + * @event ready + * @memberof OpenSeadragon.TileSource + * @type {object} + * @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event. + * @property {Object} tileSource + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( 'ready', { tileSource: readySource } ); + }; + + if( url.match(/\.js$/) ){ + //TODO: Its not very flexible to require tile sources to end jsonp + // request for info with a url that ends with '.js' but for + // now it's the only way I see to distinguish uniformly. + callbackName = url.split('/').pop().replace('.js', ''); + $.jsonp({ + url: url, + async: false, + callbackName: callbackName, + callback: callback + }); + } else { + // request info via xhr asynchronously. + $.makeAjaxRequest( { + url: url, + withCredentials: this.ajaxWithCredentials, + headers: this.ajaxHeaders, + success: function( xhr ) { + var data = processResponse( xhr ); + callback( data ); + }, + error: function ( xhr, exc ) { + var msg; + + /* + IE < 10 will block XHR requests to different origins. Any property access on the request + object will raise an exception which we'll attempt to handle by formatting the original + exception rather than the second one raised when we try to access xhr.status + */ + try { + msg = "HTTP " + xhr.status + " attempting to load TileSource"; + } catch ( e ) { + var formattedExc; + if ( typeof( exc ) == "undefined" || !exc.toString ) { + formattedExc = "Unknown error"; + } else { + formattedExc = exc.toString(); + } + + msg = formattedExc + " attempting to load TileSource"; + } + + /*** + * Raised when an error occurs loading a TileSource. + * + * @event open-failed + * @memberof OpenSeadragon.TileSource + * @type {object} + * @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event. + * @property {String} message + * @property {String} source + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( 'open-failed', { + message: msg, + source: url + }); + } + }); + } + + }, + + /** + * Responsible determining if a the particular TileSource supports the + * data format ( and allowed to apply logic against the url the data was + * loaded from, if any ). Overriding implementations are expected to do + * something smart with data and / or url to determine support. Also + * understand that iteration order of TileSources is not guarunteed so + * please make sure your data or url is expressive enough to ensure a simple + * and sufficient mechanisim for clear determination. + * @function + * @param {String|Object|Array|Document} data + * @param {String} url - the url the data was loaded + * from if any. + * @return {Boolean} + */ + supports: function( data, url ) { + return false; + }, + + /** + * Responsible for parsing and configuring the + * image metadata pertinent to this TileSources implementation. + * This method is not implemented by this class other than to throw an Error + * announcing you have to implement it. Because of the variety of tile + * server technologies, and various specifications for building image + * pyramids, this method is here to allow easy integration. + * @function + * @param {String|Object|Array|Document} data + * @param {String} url - the url the data was loaded + * from if any. + * @return {Object} options - A dictionary of keyword arguments sufficient + * to configure this tile sources constructor. + * @throws {Error} + */ + configure: function( data, url ) { + throw new Error( "Method not implemented." ); + }, + + /** + * Responsible for retrieving the url which will return an image for the + * region specified by the given x, y, and level components. + * This method is not implemented by this class other than to throw an Error + * announcing you have to implement it. Because of the variety of tile + * server technologies, and various specifications for building image + * pyramids, this method is here to allow easy integration. + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + * @throws {Error} + */ + getTileUrl: function( level, x, y ) { + throw new Error( "Method not implemented." ); + }, + + /** + * Responsible for retrieving the headers which will be attached to the image request for the + * region specified by the given x, y, and level components. + * This option is only relevant if {@link OpenSeadragon.Options}.loadTilesWithAjax is set to true. + * The headers returned here will override headers specified at the Viewer or TiledImage level. + * Specifying a falsy value for a header will clear its existing value set at the Viewer or + * TiledImage level (if any). + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + * @returns {Object} + */ + getTileAjaxHeaders: function( level, x, y ) { + return {}; + }, + + /** + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + */ + tileExists: function( level, x, y ) { + var numTiles = this.getNumTiles( level ); + return level >= this.minLevel && + level <= this.maxLevel && + x >= 0 && + y >= 0 && + x < numTiles.x && + y < numTiles.y; + } +}; + + +$.extend( true, $.TileSource.prototype, $.EventSource.prototype ); + + +/** + * Decides whether to try to process the response as xml, json, or hand back + * the text + * @private + * @inner + * @function + * @param {XMLHttpRequest} xhr - the completed network request + */ +function processResponse( xhr ){ + var responseText = xhr.responseText, + status = xhr.status, + statusText, + data; + + if ( !xhr ) { + throw new Error( $.getString( "Errors.Security" ) ); + } else if ( xhr.status !== 200 && xhr.status !== 0 ) { + status = xhr.status; + statusText = ( status == 404 ) ? + "Not Found" : + xhr.statusText; + throw new Error( $.getString( "Errors.Status", status, statusText ) ); + } + + if( responseText.match(/\s*<.*/) ){ + try{ + data = ( xhr.responseXML && xhr.responseXML.documentElement ) ? + xhr.responseXML : + $.parseXml( responseText ); + } catch (e){ + data = xhr.responseText; + } + }else if( responseText.match(/\s*[\{\[].*/) ){ + try{ + data = $.parseJSON(responseText); + } catch(e){ + data = responseText; + } + }else{ + data = responseText; + } + return data; +} + + +/** + * Determines the TileSource Implementation by introspection of OpenSeadragon + * namespace, calling each TileSource implementation of 'isType' + * @private + * @inner + * @function + * @param {Object|Array|Document} data - the tile source configuration object + * @param {String} url - the url where the tile source configuration object was + * loaded from, if any. + */ +$.TileSource.determineType = function( tileSource, data, url ){ + var property; + for( property in OpenSeadragon ){ + if( property.match(/.+TileSource$/) && + $.isFunction( OpenSeadragon[ property ] ) && + $.isFunction( OpenSeadragon[ property ].prototype.supports ) && + OpenSeadragon[ property ].prototype.supports.call( tileSource, data, url ) + ){ + return OpenSeadragon[ property ]; + } + } + + $.console.error( "No TileSource was able to open %s %s", url, data ); +}; + + +}( OpenSeadragon )); + +/* + * OpenSeadragon - DziTileSource + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class DziTileSource + * @memberof OpenSeadragon + * @extends OpenSeadragon.TileSource + * @param {Number|Object} width - the pixel width of the image or the idiomatic + * options object which is used instead of positional arguments. + * @param {Number} height + * @param {Number} tileSize + * @param {Number} tileOverlap + * @param {String} tilesUrl + * @param {String} fileFormat + * @param {OpenSeadragon.DisplayRect[]} displayRects + * @property {String} tilesUrl + * @property {String} fileFormat + * @property {OpenSeadragon.DisplayRect[]} displayRects + */ +$.DziTileSource = function( width, height, tileSize, tileOverlap, tilesUrl, fileFormat, displayRects, minLevel, maxLevel ) { + var i, + rect, + level, + options; + + if( $.isPlainObject( width ) ){ + options = width; + }else{ + options = { + width: arguments[ 0 ], + height: arguments[ 1 ], + tileSize: arguments[ 2 ], + tileOverlap: arguments[ 3 ], + tilesUrl: arguments[ 4 ], + fileFormat: arguments[ 5 ], + displayRects: arguments[ 6 ], + minLevel: arguments[ 7 ], + maxLevel: arguments[ 8 ] + }; + } + + this._levelRects = {}; + this.tilesUrl = options.tilesUrl; + this.fileFormat = options.fileFormat; + this.displayRects = options.displayRects; + + if ( this.displayRects ) { + for ( i = this.displayRects.length - 1; i >= 0; i-- ) { + rect = this.displayRects[ i ]; + for ( level = rect.minLevel; level <= rect.maxLevel; level++ ) { + if ( !this._levelRects[ level ] ) { + this._levelRects[ level ] = []; + } + this._levelRects[ level ].push( rect ); + } + } + } + + $.TileSource.apply( this, [ options ] ); + +}; + +$.extend( $.DziTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.DziTileSource.prototype */{ + + + /** + * Determine if the data and/or url imply the image service is supported by + * this tile source. + * @function + * @param {Object|Array} data + * @param {String} optional - url + */ + supports: function( data, url ){ + var ns; + if ( data.Image ) { + ns = data.Image.xmlns; + } else if ( data.documentElement) { + if ("Image" == data.documentElement.localName || "Image" == data.documentElement.tagName) { + ns = data.documentElement.namespaceURI; + } + } + + ns = (ns || '').toLowerCase(); + + return (ns.indexOf('schemas.microsoft.com/deepzoom/2008') !== -1 || + ns.indexOf('schemas.microsoft.com/deepzoom/2009') !== -1); + }, + + /** + * + * @function + * @param {Object|XMLDocument} data - the raw configuration + * @param {String} url - the url the data was retreived from if any. + * @return {Object} options - A dictionary of keyword arguments sufficient + * to configure this tile sources constructor. + */ + configure: function( data, url ){ + + var options; + + if( !$.isPlainObject(data) ){ + + options = configureFromXML( this, data ); + + }else{ + + options = configureFromObject( this, data ); + } + + if (url && !options.tilesUrl) { + options.tilesUrl = url.replace( + /([^\/]+?)(\.(dzi|xml|js)?(\?[^\/]*)?)?\/?$/, '$1_files/'); + + if (url.search(/\.(dzi|xml|js)\?/) != -1) { + options.queryParams = url.match(/\?.*/); + }else{ + options.queryParams = ''; + } + } + + return options; + }, + + + /** + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + */ + getTileUrl: function( level, x, y ) { + return [ this.tilesUrl, level, '/', x, '_', y, '.', this.fileFormat, this.queryParams ].join( '' ); + }, + + + /** + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + */ + tileExists: function( level, x, y ) { + var rects = this._levelRects[ level ], + rect, + scale, + xMin, + yMin, + xMax, + yMax, + i; + + if ( !rects || !rects.length ) { + return true; + } + + for ( i = rects.length - 1; i >= 0; i-- ) { + rect = rects[ i ]; + + if ( level < rect.minLevel || level > rect.maxLevel ) { + continue; + } + + scale = this.getLevelScale( level ); + xMin = rect.x * scale; + yMin = rect.y * scale; + xMax = xMin + rect.width * scale; + yMax = yMin + rect.height * scale; + + xMin = Math.floor( xMin / this._tileWidth ); + yMin = Math.floor( yMin / this._tileWidth ); // DZI tiles are square, so we just use _tileWidth + xMax = Math.ceil( xMax / this._tileWidth ); + yMax = Math.ceil( yMax / this._tileWidth ); + + if ( xMin <= x && x < xMax && yMin <= y && y < yMax ) { + return true; + } + } + + return false; + } +}); + + +/** + * @private + * @inner + * @function + */ +function configureFromXML( tileSource, xmlDoc ){ + + if ( !xmlDoc || !xmlDoc.documentElement ) { + throw new Error( $.getString( "Errors.Xml" ) ); + } + + var root = xmlDoc.documentElement, + rootName = root.localName || root.tagName, + ns = xmlDoc.documentElement.namespaceURI, + configuration = null, + displayRects = [], + dispRectNodes, + dispRectNode, + rectNode, + sizeNode, + i; + + if ( rootName == "Image" ) { + + try { + sizeNode = root.getElementsByTagName("Size" )[ 0 ]; + if (sizeNode === undefined) { + sizeNode = root.getElementsByTagNameNS(ns, "Size" )[ 0 ]; + } + + configuration = { + Image: { + xmlns: "http://schemas.microsoft.com/deepzoom/2008", + Url: root.getAttribute( "Url" ), + Format: root.getAttribute( "Format" ), + DisplayRect: null, + Overlap: parseInt( root.getAttribute( "Overlap" ), 10 ), + TileSize: parseInt( root.getAttribute( "TileSize" ), 10 ), + Size: { + Height: parseInt( sizeNode.getAttribute( "Height" ), 10 ), + Width: parseInt( sizeNode.getAttribute( "Width" ), 10 ) + } + } + }; + + if ( !$.imageFormatSupported( configuration.Image.Format ) ) { + throw new Error( + $.getString( "Errors.ImageFormat", configuration.Image.Format.toUpperCase() ) + ); + } + + dispRectNodes = root.getElementsByTagName("DisplayRect" ); + if (dispRectNodes === undefined) { + dispRectNodes = root.getElementsByTagNameNS(ns, "DisplayRect" )[ 0 ]; + } + + for ( i = 0; i < dispRectNodes.length; i++ ) { + dispRectNode = dispRectNodes[ i ]; + rectNode = dispRectNode.getElementsByTagName("Rect" )[ 0 ]; + if (rectNode === undefined) { + rectNode = dispRectNode.getElementsByTagNameNS(ns, "Rect" )[ 0 ]; + } + + displayRects.push({ + Rect: { + X: parseInt( rectNode.getAttribute( "X" ), 10 ), + Y: parseInt( rectNode.getAttribute( "Y" ), 10 ), + Width: parseInt( rectNode.getAttribute( "Width" ), 10 ), + Height: parseInt( rectNode.getAttribute( "Height" ), 10 ), + MinLevel: parseInt( dispRectNode.getAttribute( "MinLevel" ), 10 ), + MaxLevel: parseInt( dispRectNode.getAttribute( "MaxLevel" ), 10 ) + } + }); + } + + if( displayRects.length ){ + configuration.Image.DisplayRect = displayRects; + } + + return configureFromObject( tileSource, configuration ); + + } catch ( e ) { + throw (e instanceof Error) ? + e : + new Error( $.getString("Errors.Dzi") ); + } + } else if ( rootName == "Collection" ) { + throw new Error( $.getString( "Errors.Dzc" ) ); + } else if ( rootName == "Error" ) { + var messageNode = root.getElementsByTagName("Message")[0]; + var message = messageNode.firstChild.nodeValue; + throw new Error(message); + } + + throw new Error( $.getString( "Errors.Dzi" ) ); +} + +/** + * @private + * @inner + * @function + */ +function configureFromObject( tileSource, configuration ){ + var imageData = configuration.Image, + tilesUrl = imageData.Url, + fileFormat = imageData.Format, + sizeData = imageData.Size, + dispRectData = imageData.DisplayRect || [], + width = parseInt( sizeData.Width, 10 ), + height = parseInt( sizeData.Height, 10 ), + tileSize = parseInt( imageData.TileSize, 10 ), + tileOverlap = parseInt( imageData.Overlap, 10 ), + displayRects = [], + rectData, + i; + + //TODO: need to figure out out to better handle image format compatibility + // which actually includes additional file formats like xml and pdf + // and plain text for various tilesource implementations to avoid low + // level errors. + // + // For now, just don't perform the check. + // + /*if ( !imageFormatSupported( fileFormat ) ) { + throw new Error( + $.getString( "Errors.ImageFormat", fileFormat.toUpperCase() ) + ); + }*/ + + for ( i = 0; i < dispRectData.length; i++ ) { + rectData = dispRectData[ i ].Rect; + + displayRects.push( new $.DisplayRect( + parseInt( rectData.X, 10 ), + parseInt( rectData.Y, 10 ), + parseInt( rectData.Width, 10 ), + parseInt( rectData.Height, 10 ), + parseInt( rectData.MinLevel, 10 ), + parseInt( rectData.MaxLevel, 10 ) + )); + } + + return $.extend(true, { + width: width, /* width *required */ + height: height, /* height *required */ + tileSize: tileSize, /* tileSize *required */ + tileOverlap: tileOverlap, /* tileOverlap *required */ + minLevel: null, /* minLevel */ + maxLevel: null, /* maxLevel */ + tilesUrl: tilesUrl, /* tilesUrl */ + fileFormat: fileFormat, /* fileFormat */ + displayRects: displayRects /* displayRects */ + }, configuration ); + +} + +}( OpenSeadragon )); + +/* + * OpenSeadragon - IIIFTileSource + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class IIIFTileSource + * @classdesc A client implementation of the International Image Interoperability Framework + * Format: Image API 1.0 - 2.1 + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.TileSource + * @see http://iiif.io/api/image/ + */ +$.IIIFTileSource = function( options ){ + + /* eslint-disable camelcase */ + + $.extend( true, this, options ); + + if ( !( this.height && this.width && this['@id'] ) ) { + throw new Error( 'IIIF required parameters not provided.' ); + } + + options.tileSizePerScaleFactor = {}; + + // N.B. 2.0 renamed scale_factors to scaleFactors + if ( this.tile_width && this.tile_height ) { + options.tileWidth = this.tile_width; + options.tileHeight = this.tile_height; + } else if ( this.tile_width ) { + options.tileSize = this.tile_width; + } else if ( this.tile_height ) { + options.tileSize = this.tile_height; + } else if ( this.tiles ) { + // Version 2.0 forwards + if ( this.tiles.length == 1 ) { + options.tileWidth = this.tiles[0].width; + // Use height if provided, otherwise assume square tiles and use width. + options.tileHeight = this.tiles[0].height || this.tiles[0].width; + this.scale_factors = this.tiles[0].scaleFactors; + } else { + // Multiple tile sizes at different levels + this.scale_factors = []; + for (var t = 0; t < this.tiles.length; t++ ) { + for (var sf = 0; sf < this.tiles[t].scaleFactors.length; sf++) { + var scaleFactor = this.tiles[t].scaleFactors[sf]; + this.scale_factors.push(scaleFactor); + options.tileSizePerScaleFactor[scaleFactor] = { + width: this.tiles[t].width, + height: this.tiles[t].height || this.tiles[t].width + }; + } + } + } + } else if ( canBeTiled(options.profile) ) { + // use the largest of tileOptions that is smaller than the short dimension + var shortDim = Math.min( this.height, this.width ), + tileOptions = [256, 512, 1024], + smallerTiles = []; + + for ( var c = 0; c < tileOptions.length; c++ ) { + if ( tileOptions[c] <= shortDim ) { + smallerTiles.push( tileOptions[c] ); + } + } + + if ( smallerTiles.length > 0 ) { + options.tileSize = Math.max.apply( null, smallerTiles ); + } else { + // If we're smaller than 256, just use the short side. + options.tileSize = shortDim; + } + } else if (this.sizes && this.sizes.length > 0) { + // This info.json can't be tiled, but we can still construct a legacy pyramid from the sizes array. + // In this mode, IIIFTileSource will call functions from the abstract baseTileSource or the + // LegacyTileSource instead of performing IIIF tiling. + this.emulateLegacyImagePyramid = true; + + options.levels = constructLevels( this ); + // use the largest available size to define tiles + $.extend( true, options, { + width: options.levels[ options.levels.length - 1 ].width, + height: options.levels[ options.levels.length - 1 ].height, + tileSize: Math.max( options.height, options.width ), + tileOverlap: 0, + minLevel: 0, + maxLevel: options.levels.length - 1 + }); + this.levels = options.levels; + } else { + $.console.error("Nothing in the info.json to construct image pyramids from"); + } + + if (!options.maxLevel && !this.emulateLegacyImagePyramid) { + if (!this.scale_factors) { + options.maxLevel = Number(Math.ceil(Math.log(Math.max(this.width, this.height), 2))); + } else { + options.maxLevel = Math.floor(Math.pow(Math.max.apply(null, this.scale_factors), 0.5)); + } + } + + $.TileSource.apply( this, [ options ] ); +}; + +$.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.IIIFTileSource.prototype */{ + /** + * Determine if the data and/or url imply the image service is supported by + * this tile source. + * @function + * @param {Object|Array} data + * @param {String} optional - url + */ + + supports: function( data, url ) { + // Version 2.0 and forwards + if (data.protocol && data.protocol == 'http://iiif.io/api/image') { + return true; + // Version 1.1 + } else if ( data['@context'] && ( + data['@context'] == "http://library.stanford.edu/iiif/image-api/1.1/context.json" || + data['@context'] == "http://iiif.io/api/image/1/context.json") ) { + // N.B. the iiif.io context is wrong, but where the representation lives so likely to be used + return true; + + // Version 1.0 + } else if ( data.profile && + data.profile.indexOf("http://library.stanford.edu/iiif/image-api/compliance.html") === 0) { + return true; + } else if ( data.identifier && data.width && data.height ) { + return true; + } else if ( data.documentElement && + "info" == data.documentElement.tagName && + "http://library.stanford.edu/iiif/image-api/ns/" == + data.documentElement.namespaceURI) { + return true; + + // Not IIIF + } else { + return false; + } + }, + + /** + * + * @function + * @param {Object} data - the raw configuration + * @example IIIF 1.1 Info Looks like this + * { + * "@context" : "http://library.stanford.edu/iiif/image-api/1.1/context.json", + * "@id" : "http://iiif.example.com/prefix/1E34750D-38DB-4825-A38A-B60A345E591C", + * "width" : 6000, + * "height" : 4000, + * "scale_factors" : [ 1, 2, 4 ], + * "tile_width" : 1024, + * "tile_height" : 1024, + * "formats" : [ "jpg", "png" ], + * "qualities" : [ "native", "grey" ], + * "profile" : "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0" + * } + */ + configure: function( data, url ){ + // Try to deduce our version and fake it upwards if needed + if ( !$.isPlainObject(data) ) { + var options = configureFromXml10( data ); + options['@context'] = "http://iiif.io/api/image/1.0/context.json"; + options['@id'] = url.replace('/info.xml', ''); + return options; + } else if ( !data['@context'] ) { + data['@context'] = 'http://iiif.io/api/image/1.0/context.json'; + data['@id'] = url.replace('/info.json', ''); + return data; + } else { + return data; + } + }, + + /** + * Return the tileWidth for the given level. + * @function + * @param {Number} level + */ + getTileWidth: function( level ) { + + if(this.emulateLegacyImagePyramid) { + return $.TileSource.prototype.getTileWidth.call(this, level); + } + + var scaleFactor = Math.pow(2, this.maxLevel - level); + + if (this.tileSizePerScaleFactor && this.tileSizePerScaleFactor[scaleFactor]) { + return this.tileSizePerScaleFactor[scaleFactor].width; + } + return this._tileWidth; + }, + + /** + * Return the tileHeight for the given level. + * @function + * @param {Number} level + */ + getTileHeight: function( level ) { + + if(this.emulateLegacyImagePyramid) { + return $.TileSource.prototype.getTileHeight.call(this, level); + } + + var scaleFactor = Math.pow(2, this.maxLevel - level); + + if (this.tileSizePerScaleFactor && this.tileSizePerScaleFactor[scaleFactor]) { + return this.tileSizePerScaleFactor[scaleFactor].height; + } + return this._tileHeight; + }, + + /** + * @function + * @param {Number} level + */ + getLevelScale: function ( level ) { + + if(this.emulateLegacyImagePyramid) { + var levelScale = NaN; + if (this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel) { + levelScale = + this.levels[level].width / + this.levels[this.maxLevel].width; + } + return levelScale; + } + + return $.TileSource.prototype.getLevelScale.call(this, level); + }, + + /** + * @function + * @param {Number} level + */ + getNumTiles: function( level ) { + + if(this.emulateLegacyImagePyramid) { + var scale = this.getLevelScale(level); + if (scale) { + return new $.Point(1, 1); + } else { + return new $.Point(0, 0); + } + } + + return $.TileSource.prototype.getNumTiles.call(this, level); + }, + + + /** + * @function + * @param {Number} level + * @param {OpenSeadragon.Point} point + */ + getTileAtPoint: function( level, point ) { + + if(this.emulateLegacyImagePyramid) { + return new $.Point(0, 0); + } + + return $.TileSource.prototype.getTileAtPoint.call(this, level, point); + }, + + + /** + * Responsible for retrieving the url which will return an image for the + * region specified by the given x, y, and level components. + * @function + * @param {Number} level - z index + * @param {Number} x + * @param {Number} y + * @throws {Error} + */ + getTileUrl: function( level, x, y ){ + + if(this.emulateLegacyImagePyramid) { + var url = null; + if ( this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel ) { + url = this.levels[ level ].url; + } + return url; + } + + //# constants + var IIIF_ROTATION = '0', + //## get the scale (level as a decimal) + scale = Math.pow( 0.5, this.maxLevel - level ), + + //# image dimensions at this level + levelWidth = Math.ceil( this.width * scale ), + levelHeight = Math.ceil( this.height * scale ), + + //## iiif region + tileWidth, + tileHeight, + iiifTileSizeWidth, + iiifTileSizeHeight, + iiifRegion, + iiifTileX, + iiifTileY, + iiifTileW, + iiifTileH, + iiifSize, + iiifQuality, + uri; + + tileWidth = this.getTileWidth(level); + tileHeight = this.getTileHeight(level); + iiifTileSizeWidth = Math.ceil( tileWidth / scale ); + iiifTileSizeHeight = Math.ceil( tileHeight / scale ); + + if ( this['@context'].indexOf('/1.0/context.json') > -1 || + this['@context'].indexOf('/1.1/context.json') > -1 || + this['@context'].indexOf('/1/context.json') > -1 ) { + iiifQuality = "native.jpg"; + } else { + iiifQuality = "default.jpg"; + } + + if ( levelWidth < tileWidth && levelHeight < tileHeight ){ + iiifSize = levelWidth + ","; + iiifRegion = 'full'; + } else { + iiifTileX = x * iiifTileSizeWidth; + iiifTileY = y * iiifTileSizeHeight; + iiifTileW = Math.min( iiifTileSizeWidth, this.width - iiifTileX ); + iiifTileH = Math.min( iiifTileSizeHeight, this.height - iiifTileY ); + iiifSize = Math.ceil( iiifTileW * scale ) + ","; + iiifRegion = [ iiifTileX, iiifTileY, iiifTileW, iiifTileH ].join( ',' ); + } + uri = [ this['@id'], iiifRegion, iiifSize, IIIF_ROTATION, iiifQuality ].join( '/' ); + + return uri; + } + + }); + + /** + * Determine whether arbitrary tile requests can be made against a service with the given profile + * @function + * @param {object} profile - IIIF profile object + * @throws {Error} + */ + function canBeTiled (profile ) { + var level0Profiles = [ + "http://library.stanford.edu/iiif/image-api/compliance.html#level0", + "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0", + "http://iiif.io/api/image/2/level0.json" + ]; + var isLevel0 = (level0Profiles.indexOf(profile[0]) != -1); + return !isLevel0 || (profile.indexOf("sizeByW") != -1); + } + + /** + * Build the legacy pyramid URLs (one tile per level) + * @function + * @param {object} options - infoJson + * @throws {Error} + */ + function constructLevels(options) { + var levels = []; + for(var i = 0; i < options.sizes.length; i++) { + levels.push({ + url: options['@id'] + '/full/' + options.sizes[i].width + ',/0/default.jpg', + width: options.sizes[i].width, + height: options.sizes[i].height + }); + } + return levels.sort(function(a, b) { + return a.width - b.width; + }); + } + + + function configureFromXml10(xmlDoc) { + //parse the xml + if ( !xmlDoc || !xmlDoc.documentElement ) { + throw new Error( $.getString( "Errors.Xml" ) ); + } + + var root = xmlDoc.documentElement, + rootName = root.tagName, + configuration = null; + + if ( rootName == "info" ) { + try { + configuration = {}; + parseXML10( root, configuration ); + return configuration; + + } catch ( e ) { + throw (e instanceof Error) ? + e : + new Error( $.getString("Errors.IIIF") ); + } + } + throw new Error( $.getString( "Errors.IIIF" ) ); + } + + function parseXML10( node, configuration, property ) { + var i, + value; + if ( node.nodeType == 3 && property ) {//text node + value = node.nodeValue.trim(); + if( value.match(/^\d*$/)){ + value = Number( value ); + } + if( !configuration[ property ] ){ + configuration[ property ] = value; + }else{ + if( !$.isArray( configuration[ property ] ) ){ + configuration[ property ] = [ configuration[ property ] ]; + } + configuration[ property ].push( value ); + } + } else if( node.nodeType == 1 ){ + for( i = 0; i < node.childNodes.length; i++ ){ + parseXML10( node.childNodes[ i ], configuration, node.nodeName ); + } + } + } + + + +}( OpenSeadragon )); + +/* + * OpenSeadragon - OsmTileSource + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Derived from the OSM tile source in Rainer Simon's seajax-utils project + * . Rainer Simon has contributed + * the included code to the OpenSeadragon project under the New BSD license; + * see . + */ + + +(function( $ ){ + +/** + * @class OsmTileSource + * @classdesc A tilesource implementation for OpenStreetMap.

      + * + * Note 1. Zoomlevels. Deep Zoom and OSM define zoom levels differently. In Deep + * Zoom, level 0 equals an image of 1x1 pixels. In OSM, level 0 equals an image of + * 256x256 levels (see http://gasi.ch/blog/inside-deep-zoom-2). I.e. there is a + * difference of log2(256)=8 levels.

      + * + * Note 2. Image dimension. According to the OSM Wiki + * (http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Zoom_levels) + * the highest Mapnik zoom level has 256.144x256.144 tiles, with a 256x256 + * pixel size. I.e. the Deep Zoom image dimension is 65.572.864x65.572.864 + * pixels. + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.TileSource + * @param {Number|Object} width - the pixel width of the image or the idiomatic + * options object which is used instead of positional arguments. + * @param {Number} height + * @param {Number} tileSize + * @param {Number} tileOverlap + * @param {String} tilesUrl + */ +$.OsmTileSource = function( width, height, tileSize, tileOverlap, tilesUrl ) { + var options; + + if( $.isPlainObject( width ) ){ + options = width; + }else{ + options = { + width: arguments[0], + height: arguments[1], + tileSize: arguments[2], + tileOverlap: arguments[3], + tilesUrl: arguments[4] + }; + } + //apply default setting for standard public OpenStreatMaps service + //but allow them to be specified so fliks can host there own instance + //or apply against other services supportting the same standard + if( !options.width || !options.height ){ + options.width = 65572864; + options.height = 65572864; + } + if( !options.tileSize ){ + options.tileSize = 256; + options.tileOverlap = 0; + } + if( !options.tilesUrl ){ + options.tilesUrl = "http://tile.openstreetmap.org/"; + } + options.minLevel = 8; + + $.TileSource.apply( this, [ options ] ); + +}; + +$.extend( $.OsmTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.OsmTileSource.prototype */{ + + + /** + * Determine if the data and/or url imply the image service is supported by + * this tile source. + * @function + * @param {Object|Array} data + * @param {String} optional - url + */ + supports: function( data, url ){ + return ( + data.type && + "openstreetmaps" == data.type + ); + }, + + /** + * + * @function + * @param {Object} data - the raw configuration + * @param {String} url - the url the data was retreived from if any. + * @return {Object} options - A dictionary of keyword arguments sufficient + * to configure this tile sources constructor. + */ + configure: function( data, url ){ + return data; + }, + + + /** + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + */ + getTileUrl: function( level, x, y ) { + return this.tilesUrl + (level - 8) + "/" + x + "/" + y + ".png"; + } +}); + + +}( OpenSeadragon )); + +/* + * OpenSeadragon - TmsTileSource + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Derived from the TMS tile source in Rainer Simon's seajax-utils project + * . Rainer Simon has contributed + * the included code to the OpenSeadragon project under the New BSD license; + * see . + */ + + +(function( $ ){ + +/** + * @class TmsTileSource + * @classdesc A tilesource implementation for Tiled Map Services (TMS). + * TMS tile scheme ( [ as supported by OpenLayers ] is described here + * ( http://openlayers.org/dev/examples/tms.html ). + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.TileSource + * @param {Number|Object} width - the pixel width of the image or the idiomatic + * options object which is used instead of positional arguments. + * @param {Number} height + * @param {Number} tileSize + * @param {Number} tileOverlap + * @param {String} tilesUrl + */ +$.TmsTileSource = function( width, height, tileSize, tileOverlap, tilesUrl ) { + var options; + + if( $.isPlainObject( width ) ){ + options = width; + }else{ + options = { + width: arguments[0], + height: arguments[1], + tileSize: arguments[2], + tileOverlap: arguments[3], + tilesUrl: arguments[4] + }; + } + // TMS has integer multiples of 256 for width/height and adds buffer + // if necessary -> account for this! + var bufferedWidth = Math.ceil(options.width / 256) * 256, + bufferedHeight = Math.ceil(options.height / 256) * 256, + max; + + // Compute number of zoomlevels in this tileset + if (bufferedWidth > bufferedHeight) { + max = bufferedWidth / 256; + } else { + max = bufferedHeight / 256; + } + options.maxLevel = Math.ceil(Math.log(max) / Math.log(2)) - 1; + options.tileSize = 256; + options.width = bufferedWidth; + options.height = bufferedHeight; + + $.TileSource.apply( this, [ options ] ); + +}; + +$.extend( $.TmsTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.TmsTileSource.prototype */{ + + + /** + * Determine if the data and/or url imply the image service is supported by + * this tile source. + * @function + * @param {Object|Array} data + * @param {String} optional - url + */ + supports: function( data, url ){ + return ( data.type && "tiledmapservice" == data.type ); + }, + + /** + * + * @function + * @param {Object} data - the raw configuration + * @param {String} url - the url the data was retreived from if any. + * @return {Object} options - A dictionary of keyword arguments sufficient + * to configure this tile sources constructor. + */ + configure: function( data, url ){ + return data; + }, + + + /** + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + */ + getTileUrl: function( level, x, y ) { + // Convert from Deep Zoom definition to TMS zoom definition + var yTiles = this.getNumTiles( level ).y - 1; + + return this.tilesUrl + level + "/" + x + "/" + (yTiles - y) + ".png"; + } +}); + + +}( OpenSeadragon )); + +(function($) { + + /** + * @class ZoomifyTileSource + * @classdesc A tilesource implementation for the zoomify format. + * + * A description of the format can be found here: + * https://ecommons.cornell.edu/bitstream/handle/1813/5410/Introducing_Zoomify_Image.pdf + * + * There are two ways of creating a zoomify tilesource for openseadragon + * + * 1) Supplying all necessary information in the tilesource object. A minimal example object for this method looks like this: + * + * { + * type: "zoomifytileservice", + * width: 1000, + * height: 1000, + * tilesUrl: "/test/data/zoomify/" + * } + * + * The tileSize is currently hardcoded to 256 (the usual Zoomify default). The tileUrl must the path to the image _directory_. + * + * 2) Loading image metadata from xml file: (CURRENTLY NOT SUPPORTED) + * + * When creating zoomify formatted images one "xml" like file with name ImageProperties.xml + * will be created as well. Here is an example of such a file: + * + * + * + * To use this xml file as metadata source you must supply the path to the ImageProperties.xml file and leave out all other parameters: + * As stated above, this method of loading a zoomify tilesource is currently not supported + * + * { + * type: "zoomifytileservice", + * tilesUrl: "/test/data/zoomify/ImageProperties.xml" + * } + + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.TileSource + * @param {Number} width - the pixel width of the image. + * @param {Number} height + * @param {Number} tileSize + * @param {String} tilesUrl + */ + $.ZoomifyTileSource = function(options) { + options.tileSize = 256; + + var currentImageSize = { + x: options.width, + y: options.height + }; + options.imageSizes = [{ + x: options.width, + y: options.height + }]; + options.gridSize = [this._getGridSize(options.width, options.height, options.tileSize)]; + + while (parseInt(currentImageSize.x, 10) > options.tileSize || parseInt(currentImageSize.y, 10) > options.tileSize) { + currentImageSize.x = Math.floor(currentImageSize.x / 2); + currentImageSize.y = Math.floor(currentImageSize.y / 2); + options.imageSizes.push({ + x: currentImageSize.x, + y: currentImageSize.y + }); + options.gridSize.push(this._getGridSize(currentImageSize.x, currentImageSize.y, options.tileSize)); + } + options.imageSizes.reverse(); + options.gridSize.reverse(); + options.minLevel = 0; + options.maxLevel = options.gridSize.length - 1; + + OpenSeadragon.TileSource.apply(this, [options]); + }; + + $.extend($.ZoomifyTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.ZoomifyTileSource.prototype */ { + + //private + _getGridSize: function(width, height, tileSize) { + return { + x: Math.ceil(width / tileSize), + y: Math.ceil(height / tileSize) + }; + }, + + //private + _calculateAbsoluteTileNumber: function(level, x, y) { + var num = 0; + var size = {}; + + //Sum up all tiles below the level we want the number of tiles + for (var z = 0; z < level; z++) { + size = this.gridSize[z]; + num += size.x * size.y; + } + //Add the tiles of the level + size = this.gridSize[level]; + num += size.x * y + x; + return num; + }, + + /** + * Determine if the data and/or url imply the image service is supported by + * this tile source. + * @function + * @param {Object|Array} data + * @param {String} optional - url + */ + supports: function(data, url) { + return (data.type && "zoomifytileservice" == data.type); + }, + + /** + * + * @function + * @param {Object} data - the raw configuration + * @param {String} url - the url the data was retreived from if any. + * @return {Object} options - A dictionary of keyword arguments sufficient + * to configure this tile sources constructor. + */ + configure: function(data, url) { + return data; + }, + + /** + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + */ + getTileUrl: function(level, x, y) { + //console.log(level); + var result = 0; + var num = this._calculateAbsoluteTileNumber(level, x, y); + result = Math.floor(num / 256); + return this.tilesUrl + 'TileGroup' + result + '/' + level + '-' + x + '-' + y + '.jpg'; + + } + }); + +}(OpenSeadragon)); + + +/* + * OpenSeadragon - LegacyTileSource + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class LegacyTileSource + * @classdesc The LegacyTileSource allows simple, traditional image pyramids to be loaded + * into an OpenSeadragon Viewer. Basically, this translates to the historically + * common practice of starting with a 'master' image, maybe a tiff for example, + * and generating a set of 'service' images like one or more thumbnails, a medium + * resolution image and a high resolution image in standard web formats like + * png or jpg. + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.TileSource + * @param {Array} levels An array of file descriptions, each is an object with + * a 'url', a 'width', and a 'height'. Overriding classes can expect more + * properties but these properties are sufficient for this implementation. + * Additionally, the levels are required to be listed in order from + * smallest to largest. + * @property {Number} aspectRatio + * @property {Number} dimensions + * @property {Number} tileSize + * @property {Number} tileOverlap + * @property {Number} minLevel + * @property {Number} maxLevel + * @property {Array} levels + */ +$.LegacyTileSource = function( levels ) { + + var options, + width, + height; + + if( $.isArray( levels ) ){ + options = { + type: 'legacy-image-pyramid', + levels: levels + }; + } + + //clean up the levels to make sure we support all formats + options.levels = filterFiles( options.levels ); + + if ( options.levels.length > 0 ) { + width = options.levels[ options.levels.length - 1 ].width; + height = options.levels[ options.levels.length - 1 ].height; + } + else { + width = 0; + height = 0; + $.console.error( "No supported image formats found" ); + } + + $.extend( true, options, { + width: width, + height: height, + tileSize: Math.max( height, width ), + tileOverlap: 0, + minLevel: 0, + maxLevel: options.levels.length > 0 ? options.levels.length - 1 : 0 + } ); + + $.TileSource.apply( this, [ options ] ); + + this.levels = options.levels; +}; + +$.extend( $.LegacyTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.LegacyTileSource.prototype */{ + /** + * Determine if the data and/or url imply the image service is supported by + * this tile source. + * @function + * @param {Object|Array} data + * @param {String} optional - url + */ + supports: function( data, url ){ + return ( + data.type && + "legacy-image-pyramid" == data.type + ) || ( + data.documentElement && + "legacy-image-pyramid" == data.documentElement.getAttribute('type') + ); + }, + + + /** + * + * @function + * @param {Object|XMLDocument} configuration - the raw configuration + * @param {String} dataUrl - the url the data was retreived from if any. + * @return {Object} options - A dictionary of keyword arguments sufficient + * to configure this tile sources constructor. + */ + configure: function( configuration, dataUrl ){ + + var options; + + if( !$.isPlainObject(configuration) ){ + + options = configureFromXML( this, configuration ); + + }else{ + + options = configureFromObject( this, configuration ); + } + + return options; + + }, + + /** + * @function + * @param {Number} level + */ + getLevelScale: function ( level ) { + var levelScale = NaN; + if ( this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel ) { + levelScale = + this.levels[ level ].width / + this.levels[ this.maxLevel ].width; + } + return levelScale; + }, + + /** + * @function + * @param {Number} level + */ + getNumTiles: function( level ) { + var scale = this.getLevelScale( level ); + if ( scale ){ + return new $.Point( 1, 1 ); + } else { + return new $.Point( 0, 0 ); + } + }, + + /** + * This method is not implemented by this class other than to throw an Error + * announcing you have to implement it. Because of the variety of tile + * server technologies, and various specifications for building image + * pyramids, this method is here to allow easy integration. + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + * @throws {Error} + */ + getTileUrl: function ( level, x, y ) { + var url = null; + if ( this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel ) { + url = this.levels[ level ].url; + } + return url; + } +} ); + +/** + * This method removes any files from the Array which dont conform to our + * basic requirements for a 'level' in the LegacyTileSource. + * @private + * @inner + * @function + */ +function filterFiles( files ){ + var filtered = [], + file, + i; + for( i = 0; i < files.length; i++ ){ + file = files[ i ]; + if( file.height && + file.width && + file.url ){ + //This is sufficient to serve as a level + filtered.push({ + url: file.url, + width: Number( file.width ), + height: Number( file.height ) + }); + } + else { + $.console.error( 'Unsupported image format: %s', file.url ? file.url : '' ); + } + } + + return filtered.sort(function(a, b) { + return a.height - b.height; + }); + +} + +/** + * @private + * @inner + * @function + */ +function configureFromXML( tileSource, xmlDoc ){ + + if ( !xmlDoc || !xmlDoc.documentElement ) { + throw new Error( $.getString( "Errors.Xml" ) ); + } + + var root = xmlDoc.documentElement, + rootName = root.tagName, + conf = null, + levels = [], + level, + i; + + if ( rootName == "image" ) { + + try { + conf = { + type: root.getAttribute( "type" ), + levels: [] + }; + + levels = root.getElementsByTagName( "level" ); + for ( i = 0; i < levels.length; i++ ) { + level = levels[ i ]; + + conf.levels.push({ + url: level.getAttribute( "url" ), + width: parseInt( level.getAttribute( "width" ), 10 ), + height: parseInt( level.getAttribute( "height" ), 10 ) + }); + } + + return configureFromObject( tileSource, conf ); + + } catch ( e ) { + throw (e instanceof Error) ? + e : + new Error( 'Unknown error parsing Legacy Image Pyramid XML.' ); + } + } else if ( rootName == "collection" ) { + throw new Error( 'Legacy Image Pyramid Collections not yet supported.' ); + } else if ( rootName == "error" ) { + throw new Error( 'Error: ' + xmlDoc ); + } + + throw new Error( 'Unknown element ' + rootName ); +} + +/** + * @private + * @inner + * @function + */ +function configureFromObject( tileSource, configuration ){ + + return configuration.levels; + +} + +}( OpenSeadragon )); + +/* + * OpenSeadragon - ImageTileSource + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function ($) { + + /** + * @class ImageTileSource + * @classdesc The ImageTileSource allows a simple image to be loaded + * into an OpenSeadragon Viewer. + * There are 2 ways to open an ImageTileSource: + * 1. viewer.open({type: 'image', url: fooUrl}); + * 2. viewer.open(new OpenSeadragon.ImageTileSource({url: fooUrl})); + * + * With the first syntax, the crossOriginPolicy, ajaxWithCredentials and + * useCanvas options are inherited from the viewer if they are not + * specified directly in the options object. + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.TileSource + * @param {Object} options Options object. + * @param {String} options.url URL of the image + * @param {Boolean} [options.buildPyramid=true] If set to true (default), a + * pyramid will be built internally to provide a better downsampling. + * @param {String|Boolean} [options.crossOriginPolicy=false] Valid values are + * 'Anonymous', 'use-credentials', and false. If false, image requests will + * not use CORS preventing internal pyramid building for images from other + * domains. + * @param {String|Boolean} [options.ajaxWithCredentials=false] Whether to set + * the withCredentials XHR flag for AJAX requests (when loading tile sources). + * @param {Boolean} [options.useCanvas=true] Set to false to prevent any use + * of the canvas API. + */ + $.ImageTileSource = function (options) { + + options = $.extend({ + buildPyramid: true, + crossOriginPolicy: false, + ajaxWithCredentials: false, + useCanvas: true + }, options); + $.TileSource.apply(this, [options]); + + }; + + $.extend($.ImageTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.ImageTileSource.prototype */{ + /** + * Determine if the data and/or url imply the image service is supported by + * this tile source. + * @function + * @param {Object|Array} data + * @param {String} optional - url + */ + supports: function (data, url) { + return data.type && data.type === "image"; + }, + /** + * + * @function + * @param {Object} options - the options + * @param {String} dataUrl - the url the image was retreived from, if any. + * @return {Object} options - A dictionary of keyword arguments sufficient + * to configure this tile sources constructor. + */ + configure: function (options, dataUrl) { + return options; + }, + /** + * Responsible for retrieving, and caching the + * image metadata pertinent to this TileSources implementation. + * @function + * @param {String} url + * @throws {Error} + */ + getImageInfo: function (url) { + var image = this._image = new Image(); + var _this = this; + + if (this.crossOriginPolicy) { + image.crossOrigin = this.crossOriginPolicy; + } + if (this.ajaxWithCredentials) { + image.useCredentials = this.ajaxWithCredentials; + } + + $.addEvent(image, 'load', function () { + /* IE8 fix since it has no naturalWidth and naturalHeight */ + _this.width = Object.prototype.hasOwnProperty.call(image, 'naturalWidth') ? image.naturalWidth : image.width; + _this.height = Object.prototype.hasOwnProperty.call(image, 'naturalHeight') ? image.naturalHeight : image.height; + _this.aspectRatio = _this.width / _this.height; + _this.dimensions = new $.Point(_this.width, _this.height); + _this._tileWidth = _this.width; + _this._tileHeight = _this.height; + _this.tileOverlap = 0; + _this.minLevel = 0; + _this.levels = _this._buildLevels(); + _this.maxLevel = _this.levels.length - 1; + + _this.ready = true; + + // Note: this event is documented elsewhere, in TileSource + _this.raiseEvent('ready', {tileSource: _this}); + }); + + $.addEvent(image, 'error', function () { + // Note: this event is documented elsewhere, in TileSource + _this.raiseEvent('open-failed', { + message: "Error loading image at " + url, + source: url + }); + }); + + image.src = url; + }, + /** + * @function + * @param {Number} level + */ + getLevelScale: function (level) { + var levelScale = NaN; + if (level >= this.minLevel && level <= this.maxLevel) { + levelScale = + this.levels[level].width / + this.levels[this.maxLevel].width; + } + return levelScale; + }, + /** + * @function + * @param {Number} level + */ + getNumTiles: function (level) { + var scale = this.getLevelScale(level); + if (scale) { + return new $.Point(1, 1); + } else { + return new $.Point(0, 0); + } + }, + /** + * Retrieves a tile url + * @function + * @param {Number} level Level of the tile + * @param {Number} x x coordinate of the tile + * @param {Number} y y coordinate of the tile + */ + getTileUrl: function (level, x, y) { + var url = null; + if (level >= this.minLevel && level <= this.maxLevel) { + url = this.levels[level].url; + } + return url; + }, + /** + * Retrieves a tile context 2D + * @function + * @param {Number} level Level of the tile + * @param {Number} x x coordinate of the tile + * @param {Number} y y coordinate of the tile + */ + getContext2D: function (level, x, y) { + var context = null; + if (level >= this.minLevel && level <= this.maxLevel) { + context = this.levels[level].context2D; + } + return context; + }, + + // private + // + // Builds the differents levels of the pyramid if possible + // (i.e. if canvas API enabled and no canvas tainting issue). + _buildLevels: function () { + var levels = [{ + url: this._image.src, + /* IE8 fix since it has no naturalWidth and naturalHeight */ + width: Object.prototype.hasOwnProperty.call(this._image, 'naturalWidth') ? this._image.naturalWidth : this._image.width, + height: Object.prototype.hasOwnProperty.call(this._image, 'naturalHeight') ? this._image.naturalHeight : this._image.height + }]; + + if (!this.buildPyramid || !$.supportsCanvas || !this.useCanvas) { + // We don't need the image anymore. Allows it to be GC. + delete this._image; + return levels; + } + + /* IE8 fix since it has no naturalWidth and naturalHeight */ + var currentWidth = Object.prototype.hasOwnProperty.call(this._image, 'naturalWidth') ? this._image.naturalWidth : this._image.width; + var currentHeight = Object.prototype.hasOwnProperty.call(this._image, 'naturalHeight') ? this._image.naturalHeight : this._image.height; + + + var bigCanvas = document.createElement("canvas"); + var bigContext = bigCanvas.getContext("2d"); + + bigCanvas.width = currentWidth; + bigCanvas.height = currentHeight; + bigContext.drawImage(this._image, 0, 0, currentWidth, currentHeight); + // We cache the context of the highest level because the browser + // is a lot faster at downsampling something it already has + // downsampled before. + levels[0].context2D = bigContext; + // We don't need the image anymore. Allows it to be GC. + delete this._image; + + if ($.isCanvasTainted(bigCanvas)) { + // If the canvas is tainted, we can't compute the pyramid. + return levels; + } + + // We build smaller levels until either width or height becomes + // 1 pixel wide. + while (currentWidth >= 2 && currentHeight >= 2) { + currentWidth = Math.floor(currentWidth / 2); + currentHeight = Math.floor(currentHeight / 2); + var smallCanvas = document.createElement("canvas"); + var smallContext = smallCanvas.getContext("2d"); + smallCanvas.width = currentWidth; + smallCanvas.height = currentHeight; + smallContext.drawImage(bigCanvas, 0, 0, currentWidth, currentHeight); + + levels.splice(0, 0, { + context2D: smallContext, + width: currentWidth, + height: currentHeight + }); + + bigCanvas = smallCanvas; + bigContext = smallContext; + } + return levels; + } + }); + +}(OpenSeadragon)); + +/* + * OpenSeadragon - TileSourceCollection + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function($) { + +// deprecated +$.TileSourceCollection = function(tileSize, tileSources, rows, layout) { + $.console.error('TileSourceCollection is deprecated; use World instead'); +}; + +}(OpenSeadragon)); + +/* + * OpenSeadragon - Button + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * An enumeration of button states + * @member ButtonState + * @memberof OpenSeadragon + * @static + * @type {Object} + * @property {Number} REST + * @property {Number} GROUP + * @property {Number} HOVER + * @property {Number} DOWN + */ +$.ButtonState = { + REST: 0, + GROUP: 1, + HOVER: 2, + DOWN: 3 +}; + +/** + * @class Button + * @classdesc Manages events, hover states for individual buttons, tool-tips, as well + * as fading the buttons out when the user has not interacted with them + * for a specified period. + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.EventSource + * @param {Object} options + * @param {Element} [options.element=null] Element to use as the button. If not specified, an HTML <div> element is created. + * @param {String} [options.tooltip=null] Provides context help for the button when the + * user hovers over it. + * @param {String} [options.srcRest=null] URL of image to use in 'rest' state. + * @param {String} [options.srcGroup=null] URL of image to use in 'up' state. + * @param {String} [options.srcHover=null] URL of image to use in 'hover' state. + * @param {String} [options.srcDown=null] URL of image to use in 'down' state. + * @param {Number} [options.fadeDelay=0] How long to wait before fading. + * @param {Number} [options.fadeLength=2000] How long should it take to fade the button. + * @param {OpenSeadragon.EventHandler} [options.onPress=null] Event handler callback for {@link OpenSeadragon.Button.event:press}. + * @param {OpenSeadragon.EventHandler} [options.onRelease=null] Event handler callback for {@link OpenSeadragon.Button.event:release}. + * @param {OpenSeadragon.EventHandler} [options.onClick=null] Event handler callback for {@link OpenSeadragon.Button.event:click}. + * @param {OpenSeadragon.EventHandler} [options.onEnter=null] Event handler callback for {@link OpenSeadragon.Button.event:enter}. + * @param {OpenSeadragon.EventHandler} [options.onExit=null] Event handler callback for {@link OpenSeadragon.Button.event:exit}. + * @param {OpenSeadragon.EventHandler} [options.onFocus=null] Event handler callback for {@link OpenSeadragon.Button.event:focus}. + * @param {OpenSeadragon.EventHandler} [options.onBlur=null] Event handler callback for {@link OpenSeadragon.Button.event:blur}. + */ +$.Button = function( options ) { + + var _this = this; + + $.EventSource.call( this ); + + $.extend( true, this, { + + tooltip: null, + srcRest: null, + srcGroup: null, + srcHover: null, + srcDown: null, + clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold, + clickDistThreshold: $.DEFAULT_SETTINGS.clickDistThreshold, + /** + * How long to wait before fading. + * @member {Number} fadeDelay + * @memberof OpenSeadragon.Button# + */ + fadeDelay: 0, + /** + * How long should it take to fade the button. + * @member {Number} fadeLength + * @memberof OpenSeadragon.Button# + */ + fadeLength: 2000, + onPress: null, + onRelease: null, + onClick: null, + onEnter: null, + onExit: null, + onFocus: null, + onBlur: null + + }, options ); + + /** + * The button element. + * @member {Element} element + * @memberof OpenSeadragon.Button# + */ + this.element = options.element || $.makeNeutralElement("div"); + + //if the user has specified the element to bind the control to explicitly + //then do not add the default control images + if ( !options.element ) { + this.imgRest = $.makeTransparentImage( this.srcRest ); + this.imgGroup = $.makeTransparentImage( this.srcGroup ); + this.imgHover = $.makeTransparentImage( this.srcHover ); + this.imgDown = $.makeTransparentImage( this.srcDown ); + + this.imgRest.alt = + this.imgGroup.alt = + this.imgHover.alt = + this.imgDown.alt = + this.tooltip; + + this.element.style.position = "relative"; + $.setElementTouchActionNone( this.element ); + + this.imgGroup.style.position = + this.imgHover.style.position = + this.imgDown.style.position = + "absolute"; + + this.imgGroup.style.top = + this.imgHover.style.top = + this.imgDown.style.top = + "0px"; + + this.imgGroup.style.left = + this.imgHover.style.left = + this.imgDown.style.left = + "0px"; + + this.imgHover.style.visibility = + this.imgDown.style.visibility = + "hidden"; + + if ($.Browser.vendor == $.BROWSERS.FIREFOX && $.Browser.version < 3) { + this.imgGroup.style.top = + this.imgHover.style.top = + this.imgDown.style.top = + ""; + } + + this.element.appendChild( this.imgRest ); + this.element.appendChild( this.imgGroup ); + this.element.appendChild( this.imgHover ); + this.element.appendChild( this.imgDown ); + } + + + this.addHandler("press", this.onPress); + this.addHandler("release", this.onRelease); + this.addHandler("click", this.onClick); + this.addHandler("enter", this.onEnter); + this.addHandler("exit", this.onExit); + this.addHandler("focus", this.onFocus); + this.addHandler("blur", this.onBlur); + + /** + * The button's current state. + * @member {OpenSeadragon.ButtonState} currentState + * @memberof OpenSeadragon.Button# + */ + this.currentState = $.ButtonState.GROUP; + + // When the button last began to fade. + this.fadeBeginTime = null; + // Whether this button should fade after user stops interacting with the viewport. + this.shouldFade = false; + + this.element.style.display = "inline-block"; + this.element.style.position = "relative"; + this.element.title = this.tooltip; + + /** + * Tracks mouse/touch/key events on the button. + * @member {OpenSeadragon.MouseTracker} tracker + * @memberof OpenSeadragon.Button# + */ + this.tracker = new $.MouseTracker({ + + element: this.element, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + + enterHandler: function( event ) { + if ( event.insideElementPressed ) { + inTo( _this, $.ButtonState.DOWN ); + /** + * Raised when the cursor enters the Button element. + * + * @event enter + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( "enter", { originalEvent: event.originalEvent } ); + } else if ( !event.buttonDownAny ) { + inTo( _this, $.ButtonState.HOVER ); + } + }, + + focusHandler: function ( event ) { + this.enterHandler( event ); + /** + * Raised when the Button element receives focus. + * + * @event focus + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( "focus", { originalEvent: event.originalEvent } ); + }, + + exitHandler: function( event ) { + outTo( _this, $.ButtonState.GROUP ); + if ( event.insideElementPressed ) { + /** + * Raised when the cursor leaves the Button element. + * + * @event exit + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( "exit", { originalEvent: event.originalEvent } ); + } + }, + + blurHandler: function ( event ) { + this.exitHandler( event ); + /** + * Raised when the Button element loses focus. + * + * @event blur + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( "blur", { originalEvent: event.originalEvent } ); + }, + + pressHandler: function ( event ) { + inTo( _this, $.ButtonState.DOWN ); + /** + * Raised when a mouse button is pressed or touch occurs in the Button element. + * + * @event press + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( "press", { originalEvent: event.originalEvent } ); + }, + + releaseHandler: function( event ) { + if ( event.insideElementPressed && event.insideElementReleased ) { + outTo( _this, $.ButtonState.HOVER ); + /** + * Raised when the mouse button is released or touch ends in the Button element. + * + * @event release + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( "release", { originalEvent: event.originalEvent } ); + } else if ( event.insideElementPressed ) { + outTo( _this, $.ButtonState.GROUP ); + } else { + inTo( _this, $.ButtonState.HOVER ); + } + }, + + clickHandler: function( event ) { + if ( event.quick ) { + /** + * Raised when a mouse button is pressed and released or touch is initiated and ended in the Button element within the time and distance threshold. + * + * @event click + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent("click", { originalEvent: event.originalEvent }); + } + }, + + keyHandler: function( event ){ + //console.log( "%s : handling key %s!", _this.tooltip, event.keyCode); + if( 13 === event.keyCode ){ + /*** + * Raised when a mouse button is pressed and released or touch is initiated and ended in the Button element within the time and distance threshold. + * + * @event click + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( "click", { originalEvent: event.originalEvent } ); + /*** + * Raised when the mouse button is released or touch ends in the Button element. + * + * @event release + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( "release", { originalEvent: event.originalEvent } ); + return false; + } + return true; + } + + }); + + outTo( this, $.ButtonState.REST ); +}; + +$.extend( $.Button.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.Button.prototype */{ + + /** + * TODO: Determine what this function is intended to do and if it's actually + * useful as an API point. + * @function + */ + notifyGroupEnter: function() { + inTo( this, $.ButtonState.GROUP ); + }, + + /** + * TODO: Determine what this function is intended to do and if it's actually + * useful as an API point. + * @function + */ + notifyGroupExit: function() { + outTo( this, $.ButtonState.REST ); + }, + + /** + * @function + */ + disable: function(){ + this.notifyGroupExit(); + this.element.disabled = true; + $.setElementOpacity( this.element, 0.2, true ); + }, + + /** + * @function + */ + enable: function(){ + this.element.disabled = false; + $.setElementOpacity( this.element, 1.0, true ); + this.notifyGroupEnter(); + } + +}); + + +function scheduleFade( button ) { + $.requestAnimationFrame(function(){ + updateFade( button ); + }); +} + +function updateFade( button ) { + var currentTime, + deltaTime, + opacity; + + if ( button.shouldFade ) { + currentTime = $.now(); + deltaTime = currentTime - button.fadeBeginTime; + opacity = 1.0 - deltaTime / button.fadeLength; + opacity = Math.min( 1.0, opacity ); + opacity = Math.max( 0.0, opacity ); + + if( button.imgGroup ){ + $.setElementOpacity( button.imgGroup, opacity, true ); + } + if ( opacity > 0 ) { + // fade again + scheduleFade( button ); + } + } +} + +function beginFading( button ) { + button.shouldFade = true; + button.fadeBeginTime = $.now() + button.fadeDelay; + window.setTimeout( function(){ + scheduleFade( button ); + }, button.fadeDelay ); +} + +function stopFading( button ) { + button.shouldFade = false; + if( button.imgGroup ){ + $.setElementOpacity( button.imgGroup, 1.0, true ); + } +} + +function inTo( button, newState ) { + + if( button.element.disabled ){ + return; + } + + if ( newState >= $.ButtonState.GROUP && + button.currentState == $.ButtonState.REST ) { + stopFading( button ); + button.currentState = $.ButtonState.GROUP; + } + + if ( newState >= $.ButtonState.HOVER && + button.currentState == $.ButtonState.GROUP ) { + if( button.imgHover ){ + button.imgHover.style.visibility = ""; + } + button.currentState = $.ButtonState.HOVER; + } + + if ( newState >= $.ButtonState.DOWN && + button.currentState == $.ButtonState.HOVER ) { + if( button.imgDown ){ + button.imgDown.style.visibility = ""; + } + button.currentState = $.ButtonState.DOWN; + } +} + + +function outTo( button, newState ) { + + if( button.element.disabled ){ + return; + } + + if ( newState <= $.ButtonState.HOVER && + button.currentState == $.ButtonState.DOWN ) { + if( button.imgDown ){ + button.imgDown.style.visibility = "hidden"; + } + button.currentState = $.ButtonState.HOVER; + } + + if ( newState <= $.ButtonState.GROUP && + button.currentState == $.ButtonState.HOVER ) { + if( button.imgHover ){ + button.imgHover.style.visibility = "hidden"; + } + button.currentState = $.ButtonState.GROUP; + } + + if ( newState <= $.ButtonState.REST && + button.currentState == $.ButtonState.GROUP ) { + beginFading( button ); + button.currentState = $.ButtonState.REST; + } +} + + + +}( OpenSeadragon )); + +/* + * OpenSeadragon - ButtonGroup + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ +/** + * @class ButtonGroup + * @classdesc Manages events on groups of buttons. + * + * @memberof OpenSeadragon + * @param {Object} options - A dictionary of settings applied against the entire group of buttons. + * @param {Array} options.buttons Array of buttons + * @param {Element} [options.element] Element to use as the container + **/ +$.ButtonGroup = function( options ) { + + $.extend( true, this, { + /** + * An array containing the buttons themselves. + * @member {Array} buttons + * @memberof OpenSeadragon.ButtonGroup# + */ + buttons: [], + clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold, + clickDistThreshold: $.DEFAULT_SETTINGS.clickDistThreshold, + labelText: "" + }, options ); + + // copy the button elements TODO: Why? + var buttons = this.buttons.concat([]), + _this = this, + i; + + /** + * The shared container for the buttons. + * @member {Element} element + * @memberof OpenSeadragon.ButtonGroup# + */ + this.element = options.element || $.makeNeutralElement( "div" ); + + // TODO What if there IS an options.group specified? + if( !options.group ){ + this.label = $.makeNeutralElement( "label" ); + //TODO: support labels for ButtonGroups + //this.label.innerHTML = this.labelText; + this.element.style.display = "inline-block"; + this.element.appendChild( this.label ); + for ( i = 0; i < buttons.length; i++ ) { + this.element.appendChild( buttons[ i ].element ); + } + } + + $.setElementTouchActionNone( this.element ); + + /** + * Tracks mouse/touch/key events accross the group of buttons. + * @member {OpenSeadragon.MouseTracker} tracker + * @memberof OpenSeadragon.ButtonGroup# + */ + this.tracker = new $.MouseTracker({ + element: this.element, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + enterHandler: function ( event ) { + var i; + for ( i = 0; i < _this.buttons.length; i++ ) { + _this.buttons[ i ].notifyGroupEnter(); + } + }, + exitHandler: function ( event ) { + var i; + if ( !event.insideElementPressed ) { + for ( i = 0; i < _this.buttons.length; i++ ) { + _this.buttons[ i ].notifyGroupExit(); + } + } + }, + }); +}; + +/** @lends OpenSeadragon.ButtonGroup.prototype */ +$.ButtonGroup.prototype = { + + /** + * TODO: Figure out why this is used on the public API and if a more useful + * api can be created. + * @function + * @private + */ + emulateEnter: function() { + this.tracker.enterHandler( { eventSource: this.tracker } ); + }, + + /** + * TODO: Figure out why this is used on the public API and if a more useful + * api can be created. + * @function + * @private + */ + emulateExit: function() { + this.tracker.exitHandler( { eventSource: this.tracker } ); + } +}; + + +}( OpenSeadragon )); + +/* + * OpenSeadragon - Rect + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function($) { + +/** + * @class Rect + * @classdesc A Rectangle is described by it top left coordinates (x, y), width, + * height and degrees of rotation around (x, y). + * Note that the coordinate system used is the one commonly used with images: + * x increases when going to the right + * y increases when going to the bottom + * degrees increases clockwise with 0 being the horizontal + * + * The constructor normalizes the rectangle to always have 0 <= degrees < 90 + * + * @memberof OpenSeadragon + * @param {Number} [x=0] The vector component 'x'. + * @param {Number} [y=0] The vector component 'y'. + * @param {Number} [width=0] The vector component 'width'. + * @param {Number} [height=0] The vector component 'height'. + * @param {Number} [degrees=0] Rotation of the rectangle around (x,y) in degrees. + */ +$.Rect = function(x, y, width, height, degrees) { + /** + * The vector component 'x'. + * @member {Number} x + * @memberof OpenSeadragon.Rect# + */ + this.x = typeof(x) === "number" ? x : 0; + /** + * The vector component 'y'. + * @member {Number} y + * @memberof OpenSeadragon.Rect# + */ + this.y = typeof(y) === "number" ? y : 0; + /** + * The vector component 'width'. + * @member {Number} width + * @memberof OpenSeadragon.Rect# + */ + this.width = typeof(width) === "number" ? width : 0; + /** + * The vector component 'height'. + * @member {Number} height + * @memberof OpenSeadragon.Rect# + */ + this.height = typeof(height) === "number" ? height : 0; + + this.degrees = typeof(degrees) === "number" ? degrees : 0; + + // Normalizes the rectangle. + this.degrees = $.positiveModulo(this.degrees, 360); + var newTopLeft, newWidth; + if (this.degrees >= 270) { + newTopLeft = this.getTopRight(); + this.x = newTopLeft.x; + this.y = newTopLeft.y; + newWidth = this.height; + this.height = this.width; + this.width = newWidth; + this.degrees -= 270; + } else if (this.degrees >= 180) { + newTopLeft = this.getBottomRight(); + this.x = newTopLeft.x; + this.y = newTopLeft.y; + this.degrees -= 180; + } else if (this.degrees >= 90) { + newTopLeft = this.getBottomLeft(); + this.x = newTopLeft.x; + this.y = newTopLeft.y; + newWidth = this.height; + this.height = this.width; + this.width = newWidth; + this.degrees -= 90; + } +}; + +/** + * Builds a rectangle having the 3 specified points as summits. + * @static + * @memberof OpenSeadragon.Rect + * @param {OpenSeadragon.Point} topLeft + * @param {OpenSeadragon.Point} topRight + * @param {OpenSeadragon.Point} bottomLeft + * @returns {OpenSeadragon.Rect} + */ +$.Rect.fromSummits = function(topLeft, topRight, bottomLeft) { + var width = topLeft.distanceTo(topRight); + var height = topLeft.distanceTo(bottomLeft); + var diff = topRight.minus(topLeft); + var radians = Math.atan(diff.y / diff.x); + if (diff.x < 0) { + radians += Math.PI; + } else if (diff.y < 0) { + radians += 2 * Math.PI; + } + return new $.Rect( + topLeft.x, + topLeft.y, + width, + height, + radians / Math.PI * 180); +}; + +/** @lends OpenSeadragon.Rect.prototype */ +$.Rect.prototype = { + /** + * @function + * @returns {OpenSeadragon.Rect} a duplicate of this Rect + */ + clone: function() { + return new $.Rect( + this.x, + this.y, + this.width, + this.height, + this.degrees); + }, + + /** + * The aspect ratio is simply the ratio of width to height. + * @function + * @returns {Number} The ratio of width to height. + */ + getAspectRatio: function() { + return this.width / this.height; + }, + + /** + * Provides the coordinates of the upper-left corner of the rectangle as a + * point. + * @function + * @returns {OpenSeadragon.Point} The coordinate of the upper-left corner of + * the rectangle. + */ + getTopLeft: function() { + return new $.Point( + this.x, + this.y + ); + }, + + /** + * Provides the coordinates of the bottom-right corner of the rectangle as a + * point. + * @function + * @returns {OpenSeadragon.Point} The coordinate of the bottom-right corner of + * the rectangle. + */ + getBottomRight: function() { + return new $.Point(this.x + this.width, this.y + this.height) + .rotate(this.degrees, this.getTopLeft()); + }, + + /** + * Provides the coordinates of the top-right corner of the rectangle as a + * point. + * @function + * @returns {OpenSeadragon.Point} The coordinate of the top-right corner of + * the rectangle. + */ + getTopRight: function() { + return new $.Point(this.x + this.width, this.y) + .rotate(this.degrees, this.getTopLeft()); + }, + + /** + * Provides the coordinates of the bottom-left corner of the rectangle as a + * point. + * @function + * @returns {OpenSeadragon.Point} The coordinate of the bottom-left corner of + * the rectangle. + */ + getBottomLeft: function() { + return new $.Point(this.x, this.y + this.height) + .rotate(this.degrees, this.getTopLeft()); + }, + + /** + * Computes the center of the rectangle. + * @function + * @returns {OpenSeadragon.Point} The center of the rectangle as represented + * as represented by a 2-dimensional vector (x,y) + */ + getCenter: function() { + return new $.Point( + this.x + this.width / 2.0, + this.y + this.height / 2.0 + ).rotate(this.degrees, this.getTopLeft()); + }, + + /** + * Returns the width and height component as a vector OpenSeadragon.Point + * @function + * @returns {OpenSeadragon.Point} The 2 dimensional vector representing the + * the width and height of the rectangle. + */ + getSize: function() { + return new $.Point(this.width, this.height); + }, + + /** + * Determines if two Rectangles have equivalent components. + * @function + * @param {OpenSeadragon.Rect} rectangle The Rectangle to compare to. + * @return {Boolean} 'true' if all components are equal, otherwise 'false'. + */ + equals: function(other) { + return (other instanceof $.Rect) && + this.x === other.x && + this.y === other.y && + this.width === other.width && + this.height === other.height && + this.degrees === other.degrees; + }, + + /** + * Multiply all dimensions (except degrees) in this Rect by a factor and + * return a new Rect. + * @function + * @param {Number} factor The factor to multiply vector components. + * @returns {OpenSeadragon.Rect} A new rect representing the multiplication + * of the vector components by the factor + */ + times: function(factor) { + return new $.Rect( + this.x * factor, + this.y * factor, + this.width * factor, + this.height * factor, + this.degrees); + }, + + /** + * Translate/move this Rect by a vector and return new Rect. + * @function + * @param {OpenSeadragon.Point} delta The translation vector. + * @returns {OpenSeadragon.Rect} A new rect with altered position + */ + translate: function(delta) { + return new $.Rect( + this.x + delta.x, + this.y + delta.y, + this.width, + this.height, + this.degrees); + }, + + /** + * Returns the smallest rectangle that will contain this and the given + * rectangle bounding boxes. + * @param {OpenSeadragon.Rect} rect + * @return {OpenSeadragon.Rect} The new rectangle. + */ + union: function(rect) { + var thisBoundingBox = this.getBoundingBox(); + var otherBoundingBox = rect.getBoundingBox(); + + var left = Math.min(thisBoundingBox.x, otherBoundingBox.x); + var top = Math.min(thisBoundingBox.y, otherBoundingBox.y); + var right = Math.max( + thisBoundingBox.x + thisBoundingBox.width, + otherBoundingBox.x + otherBoundingBox.width); + var bottom = Math.max( + thisBoundingBox.y + thisBoundingBox.height, + otherBoundingBox.y + otherBoundingBox.height); + + return new $.Rect( + left, + top, + right - left, + bottom - top); + }, + + /** + * Returns the bounding box of the intersection of this rectangle with the + * given rectangle. + * @param {OpenSeadragon.Rect} rect + * @return {OpenSeadragon.Rect} the bounding box of the intersection + * or null if the rectangles don't intersect. + */ + intersection: function(rect) { + // Simplified version of Weiler Atherton clipping algorithm + // https://en.wikipedia.org/wiki/Weiler%E2%80%93Atherton_clipping_algorithm + // Because we just want the bounding box of the intersection, + // we can just compute the bounding box of: + // 1. all the summits of this which are inside rect + // 2. all the summits of rect which are inside this + // 3. all the intersections of rect and this + var EPSILON = 0.0000000001; + + var intersectionPoints = []; + + var thisTopLeft = this.getTopLeft(); + if (rect.containsPoint(thisTopLeft, EPSILON)) { + intersectionPoints.push(thisTopLeft); + } + var thisTopRight = this.getTopRight(); + if (rect.containsPoint(thisTopRight, EPSILON)) { + intersectionPoints.push(thisTopRight); + } + var thisBottomLeft = this.getBottomLeft(); + if (rect.containsPoint(thisBottomLeft, EPSILON)) { + intersectionPoints.push(thisBottomLeft); + } + var thisBottomRight = this.getBottomRight(); + if (rect.containsPoint(thisBottomRight, EPSILON)) { + intersectionPoints.push(thisBottomRight); + } + + var rectTopLeft = rect.getTopLeft(); + if (this.containsPoint(rectTopLeft, EPSILON)) { + intersectionPoints.push(rectTopLeft); + } + var rectTopRight = rect.getTopRight(); + if (this.containsPoint(rectTopRight, EPSILON)) { + intersectionPoints.push(rectTopRight); + } + var rectBottomLeft = rect.getBottomLeft(); + if (this.containsPoint(rectBottomLeft, EPSILON)) { + intersectionPoints.push(rectBottomLeft); + } + var rectBottomRight = rect.getBottomRight(); + if (this.containsPoint(rectBottomRight, EPSILON)) { + intersectionPoints.push(rectBottomRight); + } + + var thisSegments = this._getSegments(); + var rectSegments = rect._getSegments(); + for (var i = 0; i < thisSegments.length; i++) { + var thisSegment = thisSegments[i]; + for (var j = 0; j < rectSegments.length; j++) { + var rectSegment = rectSegments[j]; + var intersect = getIntersection(thisSegment[0], thisSegment[1], + rectSegment[0], rectSegment[1]); + if (intersect) { + intersectionPoints.push(intersect); + } + } + } + + // Get intersection point of segments [a,b] and [c,d] + function getIntersection(a, b, c, d) { + // http://stackoverflow.com/a/1968345/1440403 + var abVector = b.minus(a); + var cdVector = d.minus(c); + + var denom = -cdVector.x * abVector.y + abVector.x * cdVector.y; + if (denom === 0) { + return null; + } + + var s = (abVector.x * (a.y - c.y) - abVector.y * (a.x - c.x)) / denom; + var t = (cdVector.x * (a.y - c.y) - cdVector.y * (a.x - c.x)) / denom; + + if (-EPSILON <= s && s <= 1 - EPSILON && + -EPSILON <= t && t <= 1 - EPSILON) { + return new $.Point(a.x + t * abVector.x, a.y + t * abVector.y); + } + return null; + } + + if (intersectionPoints.length === 0) { + return null; + } + + var minX = intersectionPoints[0].x; + var maxX = intersectionPoints[0].x; + var minY = intersectionPoints[0].y; + var maxY = intersectionPoints[0].y; + for (var k = 1; k < intersectionPoints.length; k++) { + var point = intersectionPoints[k]; + if (point.x < minX) { + minX = point.x; + } + if (point.x > maxX) { + maxX = point.x; + } + if (point.y < minY) { + minY = point.y; + } + if (point.y > maxY) { + maxY = point.y; + } + } + return new $.Rect(minX, minY, maxX - minX, maxY - minY); + }, + + // private + _getSegments: function() { + var topLeft = this.getTopLeft(); + var topRight = this.getTopRight(); + var bottomLeft = this.getBottomLeft(); + var bottomRight = this.getBottomRight(); + return [[topLeft, topRight], + [topRight, bottomRight], + [bottomRight, bottomLeft], + [bottomLeft, topLeft]]; + }, + + /** + * Rotates a rectangle around a point. + * @function + * @param {Number} degrees The angle in degrees to rotate. + * @param {OpenSeadragon.Point} [pivot] The point about which to rotate. + * Defaults to the center of the rectangle. + * @return {OpenSeadragon.Rect} + */ + rotate: function(degrees, pivot) { + degrees = $.positiveModulo(degrees, 360); + if (degrees === 0) { + return this.clone(); + } + + pivot = pivot || this.getCenter(); + var newTopLeft = this.getTopLeft().rotate(degrees, pivot); + var newTopRight = this.getTopRight().rotate(degrees, pivot); + + var diff = newTopRight.minus(newTopLeft); + // Handle floating point error + diff = diff.apply(function(x) { + var EPSILON = 1e-15; + return Math.abs(x) < EPSILON ? 0 : x; + }); + var radians = Math.atan(diff.y / diff.x); + if (diff.x < 0) { + radians += Math.PI; + } else if (diff.y < 0) { + radians += 2 * Math.PI; + } + return new $.Rect( + newTopLeft.x, + newTopLeft.y, + this.width, + this.height, + radians / Math.PI * 180); + }, + + /** + * Retrieves the smallest horizontal (degrees=0) rectangle which contains + * this rectangle. + * @returns {OpenSeadragon.Rect} + */ + getBoundingBox: function() { + if (this.degrees === 0) { + return this.clone(); + } + var topLeft = this.getTopLeft(); + var topRight = this.getTopRight(); + var bottomLeft = this.getBottomLeft(); + var bottomRight = this.getBottomRight(); + var minX = Math.min(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x); + var maxX = Math.max(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x); + var minY = Math.min(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y); + var maxY = Math.max(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y); + return new $.Rect( + minX, + minY, + maxX - minX, + maxY - minY); + }, + + /** + * Retrieves the smallest horizontal (degrees=0) rectangle which contains + * this rectangle and has integers x, y, width and height + * @returns {OpenSeadragon.Rect} + */ + getIntegerBoundingBox: function() { + var boundingBox = this.getBoundingBox(); + var x = Math.floor(boundingBox.x); + var y = Math.floor(boundingBox.y); + var width = Math.ceil(boundingBox.width + boundingBox.x - x); + var height = Math.ceil(boundingBox.height + boundingBox.y - y); + return new $.Rect(x, y, width, height); + }, + + /** + * Determines whether a point is inside this rectangle (edge included). + * @function + * @param {OpenSeadragon.Point} point + * @param {Number} [epsilon=0] the margin of error allowed + * @returns {Boolean} true if the point is inside this rectangle, false + * otherwise. + */ + containsPoint: function(point, epsilon) { + epsilon = epsilon || 0; + + // See http://stackoverflow.com/a/2752754/1440403 for explanation + var topLeft = this.getTopLeft(); + var topRight = this.getTopRight(); + var bottomLeft = this.getBottomLeft(); + var topDiff = topRight.minus(topLeft); + var leftDiff = bottomLeft.minus(topLeft); + + return ((point.x - topLeft.x) * topDiff.x + + (point.y - topLeft.y) * topDiff.y >= -epsilon) && + + ((point.x - topRight.x) * topDiff.x + + (point.y - topRight.y) * topDiff.y <= epsilon) && + + ((point.x - topLeft.x) * leftDiff.x + + (point.y - topLeft.y) * leftDiff.y >= -epsilon) && + + ((point.x - bottomLeft.x) * leftDiff.x + + (point.y - bottomLeft.y) * leftDiff.y <= epsilon); + }, + + /** + * Provides a string representation of the rectangle which is useful for + * debugging. + * @function + * @returns {String} A string representation of the rectangle. + */ + toString: function() { + return "[" + + (Math.round(this.x * 100) / 100) + ", " + + (Math.round(this.y * 100) / 100) + ", " + + (Math.round(this.width * 100) / 100) + "x" + + (Math.round(this.height * 100) / 100) + ", " + + (Math.round(this.degrees * 100) / 100) + "deg" + + "]"; + } +}; + + +}(OpenSeadragon)); + +/* + * OpenSeadragon - ReferenceStrip + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function ( $ ) { + +// dictionary from id to private properties +var THIS = {}; + +/** + * The CollectionDrawer is a reimplementation if the Drawer API that + * focuses on allowing a viewport to be redefined as a collection + * of smaller viewports, defined by a clear number of rows and / or + * columns of which each item in the matrix of viewports has its own + * source. + * + * This idea is a reexpression of the idea of dzi collections + * which allows a clearer algorithm to reuse the tile sources already + * supported by OpenSeadragon, in heterogenious or homogenious + * sequences just like mixed groups already supported by the viewer + * for the purpose of image sequnces. + * + * TODO: The difficult part of this feature is figuring out how to express + * this functionality as a combination of the functionality already + * provided by Drawer, Viewport, TileSource, and Navigator. It may + * require better abstraction at those points in order to effeciently + * reuse those paradigms. + */ +/** + * @class ReferenceStrip + * @memberof OpenSeadragon + * @param {Object} options + */ +$.ReferenceStrip = function ( options ) { + + var _this = this, + viewer = options.viewer, + viewerSize = $.getElementSize( viewer.element ), + element, + style, + i; + + //We may need to create a new element and id if they did not + //provide the id for the existing element + if ( !options.id ) { + options.id = 'referencestrip-' + $.now(); + this.element = $.makeNeutralElement( "div" ); + this.element.id = options.id; + this.element.className = 'referencestrip'; + } + + options = $.extend( true, { + sizeRatio: $.DEFAULT_SETTINGS.referenceStripSizeRatio, + position: $.DEFAULT_SETTINGS.referenceStripPosition, + scroll: $.DEFAULT_SETTINGS.referenceStripScroll, + clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold + }, options, { + //required overrides + element: this.element, + //These need to be overridden to prevent recursion since + //the navigator is a viewer and a viewer has a navigator + showNavigator: false, + mouseNavEnabled: false, + showNavigationControl: false, + showSequenceControl: false + } ); + + $.extend( this, options ); + //Private state properties + THIS[this.id] = { + "animating": false + }; + + this.minPixelRatio = this.viewer.minPixelRatio; + + style = this.element.style; + style.marginTop = '0px'; + style.marginRight = '0px'; + style.marginBottom = '0px'; + style.marginLeft = '0px'; + style.left = '0px'; + style.bottom = '0px'; + style.border = '0px'; + style.background = '#000'; + style.position = 'relative'; + + $.setElementTouchActionNone( this.element ); + + $.setElementOpacity( this.element, 0.8 ); + + this.viewer = viewer; + this.innerTracker = new $.MouseTracker( { + element: this.element, + dragHandler: $.delegate( this, onStripDrag ), + scrollHandler: $.delegate( this, onStripScroll ), + enterHandler: $.delegate( this, onStripEnter ), + exitHandler: $.delegate( this, onStripExit ), + keyDownHandler: $.delegate( this, onKeyDown ), + keyHandler: $.delegate( this, onKeyPress ) + } ); + + //Controls the position and orientation of the reference strip and sets the + //appropriate width and height + if ( options.width && options.height ) { + this.element.style.width = options.width + 'px'; + this.element.style.height = options.height + 'px'; + viewer.addControl( + this.element, + { anchor: $.ControlAnchor.BOTTOM_LEFT } + ); + } else { + if ( "horizontal" == options.scroll ) { + this.element.style.width = ( + viewerSize.x * + options.sizeRatio * + viewer.tileSources.length + ) + ( 12 * viewer.tileSources.length ) + 'px'; + + this.element.style.height = ( + viewerSize.y * + options.sizeRatio + ) + 'px'; + + viewer.addControl( + this.element, + { anchor: $.ControlAnchor.BOTTOM_LEFT } + ); + } else { + this.element.style.height = ( + viewerSize.y * + options.sizeRatio * + viewer.tileSources.length + ) + ( 12 * viewer.tileSources.length ) + 'px'; + + this.element.style.width = ( + viewerSize.x * + options.sizeRatio + ) + 'px'; + + viewer.addControl( + this.element, + { anchor: $.ControlAnchor.TOP_LEFT } + ); + + } + } + + this.panelWidth = ( viewerSize.x * this.sizeRatio ) + 8; + this.panelHeight = ( viewerSize.y * this.sizeRatio ) + 8; + this.panels = []; + this.miniViewers = {}; + + /*jshint loopfunc:true*/ + for ( i = 0; i < viewer.tileSources.length; i++ ) { + + element = $.makeNeutralElement( 'div' ); + element.id = this.element.id + "-" + i; + + element.style.width = _this.panelWidth + 'px'; + element.style.height = _this.panelHeight + 'px'; + element.style.display = 'inline'; + element.style.float = 'left'; //Webkit + element.style.cssFloat = 'left'; //Firefox + element.style.styleFloat = 'left'; //IE + element.style.padding = '2px'; + $.setElementTouchActionNone( element ); + + element.innerTracker = new $.MouseTracker( { + element: element, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + pressHandler: function ( event ) { + event.eventSource.dragging = $.now(); + }, + releaseHandler: function ( event ) { + var tracker = event.eventSource, + id = tracker.element.id, + page = Number( id.split( '-' )[2] ), + now = $.now(); + + if ( event.insideElementPressed && + event.insideElementReleased && + tracker.dragging && + ( now - tracker.dragging ) < tracker.clickTimeThreshold ) { + tracker.dragging = null; + viewer.goToPage( page ); + } + } + } ); + + this.element.appendChild( element ); + + element.activePanel = false; + + this.panels.push( element ); + + } + loadPanels( this, this.scroll == 'vertical' ? viewerSize.y : viewerSize.x, 0 ); + this.setFocus( 0 ); + +}; + +$.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.ReferenceStrip.prototype */{ + + /** + * @function + */ + setFocus: function ( page ) { + var element = $.getElement( this.element.id + '-' + page ), + viewerSize = $.getElementSize( this.viewer.canvas ), + scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ), + scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ), + offsetLeft = -Number( this.element.style.marginLeft.replace( 'px', '' ) ), + offsetTop = -Number( this.element.style.marginTop.replace( 'px', '' ) ), + offset; + + if ( this.currentSelected !== element ) { + if ( this.currentSelected ) { + this.currentSelected.style.background = '#000'; + } + this.currentSelected = element; + this.currentSelected.style.background = '#999'; + + if ( 'horizontal' == this.scroll ) { + //right left + offset = ( Number( page ) ) * ( this.panelWidth + 3 ); + if ( offset > offsetLeft + viewerSize.x - this.panelWidth ) { + offset = Math.min( offset, ( scrollWidth - viewerSize.x ) ); + this.element.style.marginLeft = -offset + 'px'; + loadPanels( this, viewerSize.x, -offset ); + } else if ( offset < offsetLeft ) { + offset = Math.max( 0, offset - viewerSize.x / 2 ); + this.element.style.marginLeft = -offset + 'px'; + loadPanels( this, viewerSize.x, -offset ); + } + } else { + offset = ( Number( page ) ) * ( this.panelHeight + 3 ); + if ( offset > offsetTop + viewerSize.y - this.panelHeight ) { + offset = Math.min( offset, ( scrollHeight - viewerSize.y ) ); + this.element.style.marginTop = -offset + 'px'; + loadPanels( this, viewerSize.y, -offset ); + } else if ( offset < offsetTop ) { + offset = Math.max( 0, offset - viewerSize.y / 2 ); + this.element.style.marginTop = -offset + 'px'; + loadPanels( this, viewerSize.y, -offset ); + } + } + + this.currentPage = page; + onStripEnter.call( this, { eventSource: this.innerTracker } ); + } + }, + + /** + * @function + */ + update: function () { + if ( THIS[this.id].animating ) { + $.console.log( 'image reference strip update' ); + return true; + } + return false; + }, + + // Overrides Viewer.destroy + destroy: function() { + if (this.miniViewers) { + for (var key in this.miniViewers) { + this.miniViewers[key].destroy(); + } + } + + if (this.element) { + this.element.parentNode.removeChild(this.element); + } + } + +} ); + + + + +/** + * @private + * @inner + * @function + */ +function onStripDrag( event ) { + + var offsetLeft = Number( this.element.style.marginLeft.replace( 'px', '' ) ), + offsetTop = Number( this.element.style.marginTop.replace( 'px', '' ) ), + scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ), + scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ), + viewerSize = $.getElementSize( this.viewer.canvas ); + this.dragging = true; + if ( this.element ) { + if ( 'horizontal' == this.scroll ) { + if ( -event.delta.x > 0 ) { + //forward + if ( offsetLeft > -( scrollWidth - viewerSize.x ) ) { + this.element.style.marginLeft = ( offsetLeft + ( event.delta.x * 2 ) ) + 'px'; + loadPanels( this, viewerSize.x, offsetLeft + ( event.delta.x * 2 ) ); + } + } else if ( -event.delta.x < 0 ) { + //reverse + if ( offsetLeft < 0 ) { + this.element.style.marginLeft = ( offsetLeft + ( event.delta.x * 2 ) ) + 'px'; + loadPanels( this, viewerSize.x, offsetLeft + ( event.delta.x * 2 ) ); + } + } + } else { + if ( -event.delta.y > 0 ) { + //forward + if ( offsetTop > -( scrollHeight - viewerSize.y ) ) { + this.element.style.marginTop = ( offsetTop + ( event.delta.y * 2 ) ) + 'px'; + loadPanels( this, viewerSize.y, offsetTop + ( event.delta.y * 2 ) ); + } + } else if ( -event.delta.y < 0 ) { + //reverse + if ( offsetTop < 0 ) { + this.element.style.marginTop = ( offsetTop + ( event.delta.y * 2 ) ) + 'px'; + loadPanels( this, viewerSize.y, offsetTop + ( event.delta.y * 2 ) ); + } + } + } + } + return false; + +} + + + +/** + * @private + * @inner + * @function + */ +function onStripScroll( event ) { + var offsetLeft = Number( this.element.style.marginLeft.replace( 'px', '' ) ), + offsetTop = Number( this.element.style.marginTop.replace( 'px', '' ) ), + scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ), + scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ), + viewerSize = $.getElementSize( this.viewer.canvas ); + if ( this.element ) { + if ( 'horizontal' == this.scroll ) { + if ( event.scroll > 0 ) { + //forward + if ( offsetLeft > -( scrollWidth - viewerSize.x ) ) { + this.element.style.marginLeft = ( offsetLeft - ( event.scroll * 60 ) ) + 'px'; + loadPanels( this, viewerSize.x, offsetLeft - ( event.scroll * 60 ) ); + } + } else if ( event.scroll < 0 ) { + //reverse + if ( offsetLeft < 0 ) { + this.element.style.marginLeft = ( offsetLeft - ( event.scroll * 60 ) ) + 'px'; + loadPanels( this, viewerSize.x, offsetLeft - ( event.scroll * 60 ) ); + } + } + } else { + if ( event.scroll < 0 ) { + //scroll up + if ( offsetTop > viewerSize.y - scrollHeight ) { + this.element.style.marginTop = ( offsetTop + ( event.scroll * 60 ) ) + 'px'; + loadPanels( this, viewerSize.y, offsetTop + ( event.scroll * 60 ) ); + } + } else if ( event.scroll > 0 ) { + //scroll dowm + if ( offsetTop < 0 ) { + this.element.style.marginTop = ( offsetTop + ( event.scroll * 60 ) ) + 'px'; + loadPanels( this, viewerSize.y, offsetTop + ( event.scroll * 60 ) ); + } + } + } + } + //cancels event + return false; +} + + +function loadPanels( strip, viewerSize, scroll ) { + var panelSize, + activePanelsStart, + activePanelsEnd, + miniViewer, + style, + i, + element; + if ( 'horizontal' == strip.scroll ) { + panelSize = strip.panelWidth; + } else { + panelSize = strip.panelHeight; + } + activePanelsStart = Math.ceil( viewerSize / panelSize ) + 5; + activePanelsEnd = Math.ceil( ( Math.abs( scroll ) + viewerSize ) / panelSize ) + 1; + activePanelsStart = activePanelsEnd - activePanelsStart; + activePanelsStart = activePanelsStart < 0 ? 0 : activePanelsStart; + + for ( i = activePanelsStart; i < activePanelsEnd && i < strip.panels.length; i++ ) { + element = strip.panels[i]; + if ( !element.activePanel ) { + var miniTileSource; + var originalTileSource = strip.viewer.tileSources[i]; + if (originalTileSource.referenceStripThumbnailUrl) { + miniTileSource = { + type: 'image', + url: originalTileSource.referenceStripThumbnailUrl + }; + } else { + miniTileSource = originalTileSource; + } + miniViewer = new $.Viewer( { + id: element.id, + tileSources: [miniTileSource], + element: element, + navigatorSizeRatio: strip.sizeRatio, + showNavigator: false, + mouseNavEnabled: false, + showNavigationControl: false, + showSequenceControl: false, + immediateRender: true, + blendTime: 0, + animationTime: 0 + } ); + + miniViewer.displayRegion = $.makeNeutralElement( "div" ); + miniViewer.displayRegion.id = element.id + '-displayregion'; + miniViewer.displayRegion.className = 'displayregion'; + + style = miniViewer.displayRegion.style; + style.position = 'relative'; + style.top = '0px'; + style.left = '0px'; + style.fontSize = '0px'; + style.overflow = 'hidden'; + style.float = 'left'; //Webkit + style.cssFloat = 'left'; //Firefox + style.styleFloat = 'left'; //IE + style.zIndex = 999999999; + style.cursor = 'default'; + style.width = ( strip.panelWidth - 4 ) + 'px'; + style.height = ( strip.panelHeight - 4 ) + 'px'; + + // TODO: What is this for? Future keyboard navigation support? + miniViewer.displayRegion.innerTracker = new $.MouseTracker( { + element: miniViewer.displayRegion, + startDisabled: true + } ); + + element.getElementsByTagName( 'div' )[0].appendChild( + miniViewer.displayRegion + ); + + strip.miniViewers[element.id] = miniViewer; + + element.activePanel = true; + } + } +} + + +/** + * @private + * @inner + * @function + */ +function onStripEnter( event ) { + var element = event.eventSource.element; + + //$.setElementOpacity(element, 0.8); + + //element.style.border = '1px solid #555'; + //element.style.background = '#000'; + + if ( 'horizontal' == this.scroll ) { + + //element.style.paddingTop = "0px"; + element.style.marginBottom = "0px"; + + } else { + + //element.style.paddingRight = "0px"; + element.style.marginLeft = "0px"; + + } + return false; +} + + +/** + * @private + * @inner + * @function + */ +function onStripExit( event ) { + var element = event.eventSource.element; + + if ( 'horizontal' == this.scroll ) { + + //element.style.paddingTop = "10px"; + element.style.marginBottom = "-" + ( $.getElementSize( element ).y / 2 ) + "px"; + + } else { + + //element.style.paddingRight = "10px"; + element.style.marginLeft = "-" + ( $.getElementSize( element ).x / 2 ) + "px"; + + } + return false; +} + + +/** + * @private + * @inner + * @function + */ +function onKeyDown( event ) { + //console.log( event.keyCode ); + + if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { + switch ( event.keyCode ) { + case 38: //up arrow + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); + return false; + case 40: //down arrow + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); + return false; + case 37: //left arrow + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); + return false; + case 39: //right arrow + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); + return false; + default: + //console.log( 'navigator keycode %s', event.keyCode ); + return true; + } + } else { + return true; + } +} + + +/** + * @private + * @inner + * @function + */ +function onKeyPress( event ) { + //console.log( event.keyCode ); + + if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { + switch ( event.keyCode ) { + case 61: //=|+ + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); + return false; + case 45: //-|_ + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); + return false; + case 48: //0|) + case 119: //w + case 87: //W + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); + return false; + case 115: //s + case 83: //S + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); + return false; + case 97: //a + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); + return false; + case 100: //d + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); + return false; + default: + //console.log( 'navigator keycode %s', event.keyCode ); + return true; + } + } else { + return true; + } +} + +}(OpenSeadragon)); + +/* + * OpenSeadragon - DisplayRect + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class DisplayRect + * @classdesc A display rectangle is very similar to {@link OpenSeadragon.Rect} but adds two + * fields, 'minLevel' and 'maxLevel' which denote the supported zoom levels + * for this rectangle. + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.Rect + * @param {Number} x The vector component 'x'. + * @param {Number} y The vector component 'y'. + * @param {Number} width The vector component 'height'. + * @param {Number} height The vector component 'width'. + * @param {Number} minLevel The lowest zoom level supported. + * @param {Number} maxLevel The highest zoom level supported. + */ +$.DisplayRect = function( x, y, width, height, minLevel, maxLevel ) { + $.Rect.apply( this, [ x, y, width, height ] ); + + /** + * The lowest zoom level supported. + * @member {Number} minLevel + * @memberof OpenSeadragon.DisplayRect# + */ + this.minLevel = minLevel; + /** + * The highest zoom level supported. + * @member {Number} maxLevel + * @memberof OpenSeadragon.DisplayRect# + */ + this.maxLevel = maxLevel; +}; + +$.extend( $.DisplayRect.prototype, $.Rect.prototype ); + +}( OpenSeadragon )); + +/* + * OpenSeadragon - Spring + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class Spring + * @memberof OpenSeadragon + * @param {Object} options - Spring configuration settings. + * @param {Number} options.springStiffness - Spring stiffness. Must be greater than zero. + * The closer to zero, the closer to linear animation. + * @param {Number} options.animationTime - Animation duration per spring, in seconds. + * Must be zero or greater. + * @param {Number} [options.initial=0] - Initial value of spring. + * @param {Boolean} [options.exponential=false] - Whether this spring represents + * an exponential scale (such as zoom) and should be animated accordingly. Note that + * exponential springs must have non-zero values. + */ +$.Spring = function( options ) { + var args = arguments; + + if( typeof( options ) != 'object' ){ + //allows backward compatible use of ( initialValue, config ) as + //constructor parameters + options = { + initial: args.length && typeof ( args[ 0 ] ) == "number" ? + args[ 0 ] : + undefined, + /** + * Spring stiffness. + * @member {Number} springStiffness + * @memberof OpenSeadragon.Spring# + */ + springStiffness: args.length > 1 ? + args[ 1 ].springStiffness : + 5.0, + /** + * Animation duration per spring. + * @member {Number} animationTime + * @memberof OpenSeadragon.Spring# + */ + animationTime: args.length > 1 ? + args[ 1 ].animationTime : + 1.5 + }; + } + + $.console.assert(typeof options.springStiffness === "number" && options.springStiffness !== 0, + "[OpenSeadragon.Spring] options.springStiffness must be a non-zero number"); + + $.console.assert(typeof options.animationTime === "number" && options.animationTime >= 0, + "[OpenSeadragon.Spring] options.animationTime must be a number greater than or equal to 0"); + + if (options.exponential) { + this._exponential = true; + delete options.exponential; + } + + $.extend( true, this, options); + + /** + * @member {Object} current + * @memberof OpenSeadragon.Spring# + * @property {Number} value + * @property {Number} time + */ + this.current = { + value: typeof ( this.initial ) == "number" ? + this.initial : + (this._exponential ? 0 : 1), + time: $.now() // always work in milliseconds + }; + + $.console.assert(!this._exponential || this.current.value !== 0, + "[OpenSeadragon.Spring] value must be non-zero for exponential springs"); + + /** + * @member {Object} start + * @memberof OpenSeadragon.Spring# + * @property {Number} value + * @property {Number} time + */ + this.start = { + value: this.current.value, + time: this.current.time + }; + + /** + * @member {Object} target + * @memberof OpenSeadragon.Spring# + * @property {Number} value + * @property {Number} time + */ + this.target = { + value: this.current.value, + time: this.current.time + }; + + if (this._exponential) { + this.start._logValue = Math.log(this.start.value); + this.target._logValue = Math.log(this.target.value); + this.current._logValue = Math.log(this.current.value); + } +}; + +/** @lends OpenSeadragon.Spring.prototype */ +$.Spring.prototype = { + + /** + * @function + * @param {Number} target + */ + resetTo: function( target ) { + $.console.assert(!this._exponential || target !== 0, + "[OpenSeadragon.Spring.resetTo] target must be non-zero for exponential springs"); + + this.start.value = this.target.value = this.current.value = target; + this.start.time = this.target.time = this.current.time = $.now(); + + if (this._exponential) { + this.start._logValue = Math.log(this.start.value); + this.target._logValue = Math.log(this.target.value); + this.current._logValue = Math.log(this.current.value); + } + }, + + /** + * @function + * @param {Number} target + */ + springTo: function( target ) { + $.console.assert(!this._exponential || target !== 0, + "[OpenSeadragon.Spring.springTo] target must be non-zero for exponential springs"); + + this.start.value = this.current.value; + this.start.time = this.current.time; + this.target.value = target; + this.target.time = this.start.time + 1000 * this.animationTime; + + if (this._exponential) { + this.start._logValue = Math.log(this.start.value); + this.target._logValue = Math.log(this.target.value); + } + }, + + /** + * @function + * @param {Number} delta + */ + shiftBy: function( delta ) { + this.start.value += delta; + this.target.value += delta; + + if (this._exponential) { + $.console.assert(this.target.value !== 0 && this.start.value !== 0, + "[OpenSeadragon.Spring.shiftBy] spring value must be non-zero for exponential springs"); + + this.start._logValue = Math.log(this.start.value); + this.target._logValue = Math.log(this.target.value); + } + }, + + setExponential: function(value) { + this._exponential = value; + + if (this._exponential) { + $.console.assert(this.current.value !== 0 && this.target.value !== 0 && this.start.value !== 0, + "[OpenSeadragon.Spring.setExponential] spring value must be non-zero for exponential springs"); + + this.start._logValue = Math.log(this.start.value); + this.target._logValue = Math.log(this.target.value); + this.current._logValue = Math.log(this.current.value); + } + }, + + /** + * @function + * @returns true if the value got updated, false otherwise + */ + update: function() { + this.current.time = $.now(); + + var startValue, targetValue; + if (this._exponential) { + startValue = this.start._logValue; + targetValue = this.target._logValue; + } else { + startValue = this.start.value; + targetValue = this.target.value; + } + + var currentValue = (this.current.time >= this.target.time) ? + targetValue : + startValue + + ( targetValue - startValue ) * + transform( + this.springStiffness, + ( this.current.time - this.start.time ) / + ( this.target.time - this.start.time ) + ); + + var oldValue = this.current.value; + if (this._exponential) { + this.current.value = Math.exp(currentValue); + } else { + this.current.value = currentValue; + } + + return oldValue != this.current.value; + }, + + /** + * Returns whether the spring is at the target value + * @function + * @returns {Boolean} True if at target value, false otherwise + */ + isAtTargetValue: function() { + return this.current.value === this.target.value; + } +}; + +/** + * @private + */ +function transform( stiffness, x ) { + return ( 1.0 - Math.exp( stiffness * -x ) ) / + ( 1.0 - Math.exp( -stiffness ) ); +} + +}( OpenSeadragon )); + +/* + * OpenSeadragon - ImageLoader + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function($){ + +/** + * @private + * @class ImageJob + * @classdesc Handles downloading of a single image. + * @param {Object} options - Options for this ImageJob. + * @param {String} [options.src] - URL of image to download. + * @param {String} [options.loadWithAjax] - Whether to load this image with AJAX. + * @param {String} [options.ajaxHeaders] - Headers to add to the image request if using AJAX. + * @param {String} [options.crossOriginPolicy] - CORS policy to use for downloads + * @param {Function} [options.callback] - Called once image has been downloaded. + * @param {Function} [options.abort] - Called when this image job is aborted. + * @param {Number} [options.timeout] - The max number of milliseconds that this image job may take to complete. + */ +function ImageJob (options) { + + $.extend(true, this, { + timeout: $.DEFAULT_SETTINGS.timeout, + jobId: null + }, options); + + /** + * Image object which will contain downloaded image. + * @member {Image} image + * @memberof OpenSeadragon.ImageJob# + */ + this.image = null; +} + +ImageJob.prototype = { + errorMsg: null, + + /** + * Starts the image job. + * @method + */ + start: function(){ + var self = this; + var selfAbort = this.abort; + + this.image = new Image(); + + this.image.onload = function(){ + self.finish(true); + }; + this.image.onabort = this.image.onerror = function() { + self.errorMsg = "Image load aborted"; + self.finish(false); + }; + + this.jobId = window.setTimeout(function(){ + self.errorMsg = "Image load exceeded timeout"; + self.finish(false); + }, this.timeout); + + // Load the tile with an AJAX request if the loadWithAjax option is + // set. Otherwise load the image by setting the source proprety of the image object. + if (this.loadWithAjax) { + this.request = $.makeAjaxRequest({ + url: this.src, + withCredentials: this.ajaxWithCredentials, + headers: this.ajaxHeaders, + responseType: "arraybuffer", + success: function(request) { + var blb; + // Make the raw data into a blob. + // BlobBuilder fallback adapted from + // http://stackoverflow.com/questions/15293694/blob-constructor-browser-compatibility + try { + blb = new window.Blob([request.response]); + } catch (e) { + var BlobBuilder = ( + window.BlobBuilder || + window.WebKitBlobBuilder || + window.MozBlobBuilder || + window.MSBlobBuilder + ); + if (e.name === 'TypeError' && BlobBuilder) { + var bb = new BlobBuilder(); + bb.append(request.response); + blb = bb.getBlob(); + } + } + // If the blob is empty for some reason consider the image load a failure. + if (blb.size === 0) { + self.errorMsg = "Empty image response."; + self.finish(false); + } + // Create a URL for the blob data and make it the source of the image object. + // This will still trigger Image.onload to indicate a successful tile load. + var url = (window.URL || window.webkitURL).createObjectURL(blb); + self.image.src = url; + }, + error: function(request) { + self.errorMsg = "Image load aborted - XHR error"; + self.finish(false); + } + }); + + // Provide a function to properly abort the request. + this.abort = function() { + self.request.abort(); + + // Call the existing abort function if available + if (typeof selfAbort === "function") { + selfAbort(); + } + }; + } else { + if (this.crossOriginPolicy !== false) { + this.image.crossOrigin = this.crossOriginPolicy; + } + + this.image.src = this.src; + } + }, + + finish: function(successful) { + this.image.onload = this.image.onerror = this.image.onabort = null; + if (!successful) { + this.image = null; + } + + if (this.jobId) { + window.clearTimeout(this.jobId); + } + + this.callback(this); + } + +}; + +/** + * @class ImageLoader + * @memberof OpenSeadragon + * @classdesc Handles downloading of a set of images using asynchronous queue pattern. + * You generally won't have to interact with the ImageLoader directly. + * @param {Object} options - Options for this ImageLoader. + * @param {Number} [options.jobLimit] - The number of concurrent image requests. See imageLoaderLimit in {@link OpenSeadragon.Options} for details. + * @param {Number} [options.timeout] - The max number of milliseconds that an image job may take to complete. + */ +$.ImageLoader = function(options) { + + $.extend(true, this, { + jobLimit: $.DEFAULT_SETTINGS.imageLoaderLimit, + timeout: $.DEFAULT_SETTINGS.timeout, + jobQueue: [], + jobsInProgress: 0 + }, options); + +}; + +/** @lends OpenSeadragon.ImageLoader.prototype */ +$.ImageLoader.prototype = { + + /** + * Add an unloaded image to the loader queue. + * @method + * @param {Object} options - Options for this job. + * @param {String} [options.src] - URL of image to download. + * @param {String} [options.loadWithAjax] - Whether to load this image with AJAX. + * @param {String} [options.ajaxHeaders] - Headers to add to the image request if using AJAX. + * @param {String|Boolean} [options.crossOriginPolicy] - CORS policy to use for downloads + * @param {Boolean} [options.ajaxWithCredentials] - Whether to set withCredentials on AJAX + * requests. + * @param {Function} [options.callback] - Called once image has been downloaded. + * @param {Function} [options.abort] - Called when this image job is aborted. + */ + addJob: function(options) { + var _this = this, + complete = function(job) { + completeJob(_this, job, options.callback); + }, + jobOptions = { + src: options.src, + loadWithAjax: options.loadWithAjax, + ajaxHeaders: options.loadWithAjax ? options.ajaxHeaders : null, + crossOriginPolicy: options.crossOriginPolicy, + ajaxWithCredentials: options.ajaxWithCredentials, + callback: complete, + abort: options.abort, + timeout: this.timeout + }, + newJob = new ImageJob(jobOptions); + + if ( !this.jobLimit || this.jobsInProgress < this.jobLimit ) { + newJob.start(); + this.jobsInProgress++; + } + else { + this.jobQueue.push( newJob ); + } + }, + + /** + * Clear any unstarted image loading jobs from the queue. + * @method + */ + clear: function() { + for( var i = 0; i < this.jobQueue.length; i++ ) { + var job = this.jobQueue[i]; + if ( typeof job.abort === "function" ) { + job.abort(); + } + } + + this.jobQueue = []; + } +}; + +/** + * Cleans up ImageJob once completed. + * @method + * @private + * @param loader - ImageLoader used to start job. + * @param job - The ImageJob that has completed. + * @param callback - Called once cleanup is finished. + */ +function completeJob(loader, job, callback) { + var nextJob; + + loader.jobsInProgress--; + + if ((!loader.jobLimit || loader.jobsInProgress < loader.jobLimit) && loader.jobQueue.length > 0) { + nextJob = loader.jobQueue.shift(); + nextJob.start(); + loader.jobsInProgress++; + } + + callback(job.image, job.errorMsg, job.request); +} + +}(OpenSeadragon)); + +/* + * OpenSeadragon - Tile + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class Tile + * @memberof OpenSeadragon + * @param {Number} level The zoom level this tile belongs to. + * @param {Number} x The vector component 'x'. + * @param {Number} y The vector component 'y'. + * @param {OpenSeadragon.Point} bounds Where this tile fits, in normalized + * coordinates. + * @param {Boolean} exists Is this tile a part of a sparse image? ( Also has + * this tile failed to load? ) + * @param {String} url The URL of this tile's image. + * @param {CanvasRenderingContext2D} context2D The context2D of this tile if it + * is provided directly by the tile source. + * @param {Boolean} loadWithAjax Whether this tile image should be loaded with an AJAX request . + * @param {Object} ajaxHeaders The headers to send with this tile's AJAX request (if applicable). + */ +$.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, ajaxHeaders) { + /** + * The zoom level this tile belongs to. + * @member {Number} level + * @memberof OpenSeadragon.Tile# + */ + this.level = level; + /** + * The vector component 'x'. + * @member {Number} x + * @memberof OpenSeadragon.Tile# + */ + this.x = x; + /** + * The vector component 'y'. + * @member {Number} y + * @memberof OpenSeadragon.Tile# + */ + this.y = y; + /** + * Where this tile fits, in normalized coordinates + * @member {OpenSeadragon.Rect} bounds + * @memberof OpenSeadragon.Tile# + */ + this.bounds = bounds; + /** + * Is this tile a part of a sparse image? Also has this tile failed to load? + * @member {Boolean} exists + * @memberof OpenSeadragon.Tile# + */ + this.exists = exists; + /** + * The URL of this tile's image. + * @member {String} url + * @memberof OpenSeadragon.Tile# + */ + this.url = url; + /** + * The context2D of this tile if it is provided directly by the tile source. + * @member {CanvasRenderingContext2D} context2D + * @memberOf OpenSeadragon.Tile# + */ + this.context2D = context2D; + /** + * Whether to load this tile's image with an AJAX request. + * @member {Boolean} loadWithAjax + * @memberof OpenSeadragon.Tile# + */ + this.loadWithAjax = loadWithAjax; + /** + * The headers to be used in requesting this tile's image. + * Only used if loadWithAjax is set to true. + * @member {Object} ajaxHeaders + * @memberof OpenSeadragon.Tile# + */ + this.ajaxHeaders = ajaxHeaders; + /** + * The unique cache key for this tile. + * @member {String} cacheKey + * @memberof OpenSeadragon.Tile# + */ + if (this.ajaxHeaders) { + this.cacheKey = this.url + "+" + JSON.stringify(this.ajaxHeaders); + } else { + this.cacheKey = this.url; + } + /** + * Is this tile loaded? + * @member {Boolean} loaded + * @memberof OpenSeadragon.Tile# + */ + this.loaded = false; + /** + * Is this tile loading? + * @member {Boolean} loading + * @memberof OpenSeadragon.Tile# + */ + this.loading = false; + + /** + * The HTML div element for this tile + * @member {Element} element + * @memberof OpenSeadragon.Tile# + */ + this.element = null; + /** + * The HTML img element for this tile. + * @member {Element} imgElement + * @memberof OpenSeadragon.Tile# + */ + this.imgElement = null; + /** + * The Image object for this tile. + * @member {Object} image + * @memberof OpenSeadragon.Tile# + */ + this.image = null; + + /** + * The alias of this.element.style. + * @member {String} style + * @memberof OpenSeadragon.Tile# + */ + this.style = null; + /** + * This tile's position on screen, in pixels. + * @member {OpenSeadragon.Point} position + * @memberof OpenSeadragon.Tile# + */ + this.position = null; + /** + * This tile's size on screen, in pixels. + * @member {OpenSeadragon.Point} size + * @memberof OpenSeadragon.Tile# + */ + this.size = null; + /** + * The start time of this tile's blending. + * @member {Number} blendStart + * @memberof OpenSeadragon.Tile# + */ + this.blendStart = null; + /** + * The current opacity this tile should be. + * @member {Number} opacity + * @memberof OpenSeadragon.Tile# + */ + this.opacity = null; + /** + * The squared distance of this tile to the viewport center. + * Use for comparing tiles. + * @private + * @member {Number} squaredDistance + * @memberof OpenSeadragon.Tile# + */ + this.squaredDistance = null; + /** + * The visibility score of this tile. + * @member {Number} visibility + * @memberof OpenSeadragon.Tile# + */ + this.visibility = null; + + /** + * Whether this tile is currently being drawn. + * @member {Boolean} beingDrawn + * @memberof OpenSeadragon.Tile# + */ + this.beingDrawn = false; + + /** + * Timestamp the tile was last touched. + * @member {Number} lastTouchTime + * @memberof OpenSeadragon.Tile# + */ + this.lastTouchTime = 0; + + /** + * Whether this tile is in the right-most column for its level. + * @member {Boolean} isRightMost + * @memberof OpenSeadragon.Tile# + */ + this.isRightMost = false; + + /** + * Whether this tile is in the bottom-most row for its level. + * @member {Boolean} isBottomMost + * @memberof OpenSeadragon.Tile# + */ + this.isBottomMost = false; +}; + +/** @lends OpenSeadragon.Tile.prototype */ +$.Tile.prototype = { + + /** + * Provides a string representation of this tiles level and (x,y) + * components. + * @function + * @returns {String} + */ + toString: function() { + return this.level + "/" + this.x + "_" + this.y; + }, + + // private + _hasTransparencyChannel: function() { + return !!this.context2D || this.url.match('.png'); + }, + + /** + * Renders the tile in an html container. + * @function + * @param {Element} container + */ + drawHTML: function( container ) { + if (!this.cacheImageRecord) { + $.console.warn( + '[Tile.drawHTML] attempting to draw tile %s when it\'s not cached', + this.toString()); + return; + } + + if ( !this.loaded ) { + $.console.warn( + "Attempting to draw tile %s when it's not yet loaded.", + this.toString() + ); + return; + } + + //EXPERIMENTAL - trying to figure out how to scale the container + // content during animation of the container size. + + if ( !this.element ) { + this.element = $.makeNeutralElement( "div" ); + this.imgElement = this.cacheImageRecord.getImage().cloneNode(); + this.imgElement.style.msInterpolationMode = "nearest-neighbor"; + this.imgElement.style.width = "100%"; + this.imgElement.style.height = "100%"; + + this.style = this.element.style; + this.style.position = "absolute"; + } + if ( this.element.parentNode != container ) { + container.appendChild( this.element ); + } + if ( this.imgElement.parentNode != this.element ) { + this.element.appendChild( this.imgElement ); + } + + this.style.top = this.position.y + "px"; + this.style.left = this.position.x + "px"; + this.style.height = this.size.y + "px"; + this.style.width = this.size.x + "px"; + + $.setElementOpacity( this.element, this.opacity ); + }, + + /** + * Renders the tile in a canvas-based context. + * @function + * @param {Canvas} context + * @param {Function} drawingHandler - Method for firing the drawing event. + * drawingHandler({context, tile, rendered}) + * where rendered is the context with the pre-drawn image. + * @param {Number} [scale=1] - Apply a scale to position and size + * @param {OpenSeadragon.Point} [translate] - A translation vector + */ + drawCanvas: function( context, drawingHandler, scale, translate ) { + + var position = this.position.times($.pixelDensityRatio), + size = this.size.times($.pixelDensityRatio), + rendered; + + if (!this.context2D && !this.cacheImageRecord) { + $.console.warn( + '[Tile.drawCanvas] attempting to draw tile %s when it\'s not cached', + this.toString()); + return; + } + + rendered = this.context2D || this.cacheImageRecord.getRenderedContext(); + + if ( !this.loaded || !rendered ){ + $.console.warn( + "Attempting to draw tile %s when it's not yet loaded.", + this.toString() + ); + + return; + } + + context.save(); + + context.globalAlpha = this.opacity; + + if (typeof scale === 'number' && scale !== 1) { + // draw tile at a different scale + position = position.times(scale); + size = size.times(scale); + } + + if (translate instanceof $.Point) { + // shift tile position slightly + position = position.plus(translate); + } + + //if we are supposed to be rendering fully opaque rectangle, + //ie its done fading or fading is turned off, and if we are drawing + //an image with an alpha channel, then the only way + //to avoid seeing the tile underneath is to clear the rectangle + if (context.globalAlpha === 1 && this._hasTransparencyChannel()) { + //clearing only the inside of the rectangle occupied + //by the png prevents edge flikering + context.clearRect( + position.x + 1, + position.y + 1, + size.x - 2, + size.y - 2 + ); + } + + // This gives the application a chance to make image manipulation + // changes as we are rendering the image + drawingHandler({context: context, tile: this, rendered: rendered}); + + context.drawImage( + rendered.canvas, + 0, + 0, + rendered.canvas.width, + rendered.canvas.height, + position.x, + position.y, + size.x, + size.y + ); + + context.restore(); + }, + + /** + * Get the ratio between current and original size. + * @function + * @return {Float} + */ + getScaleForEdgeSmoothing: function() { + var context; + if (this.cacheImageRecord) { + context = this.cacheImageRecord.getRenderedContext(); + } else if (this.context2D) { + context = this.context2D; + } else { + $.console.warn( + '[Tile.drawCanvas] attempting to get tile scale %s when tile\'s not cached', + this.toString()); + return 1; + } + return context.canvas.width / (this.size.x * $.pixelDensityRatio); + }, + + /** + * Get a translation vector that when applied to the tile position produces integer coordinates. + * Needed to avoid swimming and twitching. + * @function + * @param {Number} [scale=1] - Scale to be applied to position. + * @return {OpenSeadragon.Point} + */ + getTranslationForEdgeSmoothing: function(scale, canvasSize, sketchCanvasSize) { + // The translation vector must have positive values, otherwise the image goes a bit off + // the sketch canvas to the top and left and we must use negative coordinates to repaint it + // to the main canvas. In that case, some browsers throw: + // INDEX_SIZE_ERR: DOM Exception 1: Index or size was negative, or greater than the allowed value. + var x = Math.max(1, Math.ceil((sketchCanvasSize.x - canvasSize.x) / 2)); + var y = Math.max(1, Math.ceil((sketchCanvasSize.y - canvasSize.y) / 2)); + return new $.Point(x, y).minus( + this.position + .times($.pixelDensityRatio) + .times(scale || 1) + .apply(function(x) { + return x % 1; + }) + ); + }, + + /** + * Removes tile from its container. + * @function + */ + unload: function() { + if ( this.imgElement && this.imgElement.parentNode ) { + this.imgElement.parentNode.removeChild( this.imgElement ); + } + if ( this.element && this.element.parentNode ) { + this.element.parentNode.removeChild( this.element ); + } + + this.element = null; + this.imgElement = null; + this.loaded = false; + this.loading = false; + } +}; + +}( OpenSeadragon )); + +/* + * OpenSeadragon - Overlay + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function($) { + + /** + * An enumeration of positions that an overlay may be assigned relative to + * the viewport. + * It is identical to OpenSeadragon.Placement but is kept for backward + * compatibility. + * @member OverlayPlacement + * @memberof OpenSeadragon + * @see OpenSeadragon.Placement + * @static + * @readonly + * @type {Object} + * @property {Number} CENTER + * @property {Number} TOP_LEFT + * @property {Number} TOP + * @property {Number} TOP_RIGHT + * @property {Number} RIGHT + * @property {Number} BOTTOM_RIGHT + * @property {Number} BOTTOM + * @property {Number} BOTTOM_LEFT + * @property {Number} LEFT + */ + $.OverlayPlacement = $.Placement; + + /** + * An enumeration of possible ways to handle overlays rotation + * @member OverlayRotationMode + * @memberOf OpenSeadragon + * @static + * @readonly + * @property {Number} NO_ROTATION The overlay ignore the viewport rotation. + * @property {Number} EXACT The overlay use CSS 3 transforms to rotate with + * the viewport. If the overlay contains text, it will get rotated as well. + * @property {Number} BOUNDING_BOX The overlay adjusts for rotation by + * taking the size of the bounding box of the rotated bounds. + * Only valid for overlays with Rect location and scalable in both directions. + */ + $.OverlayRotationMode = $.freezeObject({ + NO_ROTATION: 1, + EXACT: 2, + BOUNDING_BOX: 3 + }); + + /** + * @class Overlay + * @classdesc Provides a way to float an HTML element on top of the viewer element. + * + * @memberof OpenSeadragon + * @param {Object} options + * @param {Element} options.element + * @param {OpenSeadragon.Point|OpenSeadragon.Rect} options.location - The + * location of the overlay on the image. If a {@link OpenSeadragon.Point} + * is specified, the overlay will be located at this location with respect + * to the placement option. If a {@link OpenSeadragon.Rect} is specified, + * the overlay will be placed at this location with the corresponding width + * and height and placement TOP_LEFT. + * @param {OpenSeadragon.Placement} [options.placement=OpenSeadragon.Placement.TOP_LEFT] + * Defines what part of the overlay should be at the specified options.location + * @param {OpenSeadragon.Overlay.OnDrawCallback} [options.onDraw] + * @param {Boolean} [options.checkResize=true] Set to false to avoid to + * check the size of the overlay everytime it is drawn in the directions + * which are not scaled. It will improve performances but will cause a + * misalignment if the overlay size changes. + * @param {Number} [options.width] The width of the overlay in viewport + * coordinates. If specified, the width of the overlay will be adjusted when + * the zoom changes. + * @param {Number} [options.height] The height of the overlay in viewport + * coordinates. If specified, the height of the overlay will be adjusted when + * the zoom changes. + * @param {Boolean} [options.rotationMode=OpenSeadragon.OverlayRotationMode.EXACT] + * How to handle the rotation of the viewport. + */ + $.Overlay = function(element, location, placement) { + + /** + * onDraw callback signature used by {@link OpenSeadragon.Overlay}. + * + * @callback OnDrawCallback + * @memberof OpenSeadragon.Overlay + * @param {OpenSeadragon.Point} position + * @param {OpenSeadragon.Point} size + * @param {Element} element + */ + + var options; + if ($.isPlainObject(element)) { + options = element; + } else { + options = { + element: element, + location: location, + placement: placement + }; + } + + this.element = options.element; + this.style = options.element.style; + this._init(options); + }; + + /** @lends OpenSeadragon.Overlay.prototype */ + $.Overlay.prototype = { + + // private + _init: function(options) { + this.location = options.location; + this.placement = options.placement === undefined ? + $.Placement.TOP_LEFT : options.placement; + this.onDraw = options.onDraw; + this.checkResize = options.checkResize === undefined ? + true : options.checkResize; + + // When this.width is not null, the overlay get scaled horizontally + this.width = options.width === undefined ? null : options.width; + + // When this.height is not null, the overlay get scaled vertically + this.height = options.height === undefined ? null : options.height; + + this.rotationMode = options.rotationMode || $.OverlayRotationMode.EXACT; + + // Having a rect as location is a syntactic sugar + if (this.location instanceof $.Rect) { + this.width = this.location.width; + this.height = this.location.height; + this.location = this.location.getTopLeft(); + this.placement = $.Placement.TOP_LEFT; + } + + // Deprecated properties kept for backward compatibility. + this.scales = this.width !== null && this.height !== null; + this.bounds = new $.Rect( + this.location.x, this.location.y, this.width, this.height); + this.position = this.location; + }, + + /** + * Internal function to adjust the position of an overlay + * depending on it size and placement. + * @function + * @param {OpenSeadragon.Point} position + * @param {OpenSeadragon.Point} size + */ + adjust: function(position, size) { + var properties = $.Placement.properties[this.placement]; + if (!properties) { + return; + } + if (properties.isHorizontallyCentered) { + position.x -= size.x / 2; + } else if (properties.isRight) { + position.x -= size.x; + } + if (properties.isVerticallyCentered) { + position.y -= size.y / 2; + } else if (properties.isBottom) { + position.y -= size.y; + } + }, + + /** + * @function + */ + destroy: function() { + var element = this.element; + var style = this.style; + + if (element.parentNode) { + element.parentNode.removeChild(element); + //this should allow us to preserve overlays when required between + //pages + if (element.prevElementParent) { + style.display = 'none'; + //element.prevElementParent.insertBefore( + // element, + // element.prevNextSibling + //); + document.body.appendChild(element); + } + } + + // clear the onDraw callback + this.onDraw = null; + + style.top = ""; + style.left = ""; + style.position = ""; + + if (this.width !== null) { + style.width = ""; + } + if (this.height !== null) { + style.height = ""; + } + var transformOriginProp = $.getCssPropertyWithVendorPrefix( + 'transformOrigin'); + var transformProp = $.getCssPropertyWithVendorPrefix( + 'transform'); + if (transformOriginProp && transformProp) { + style[transformOriginProp] = ""; + style[transformProp] = ""; + } + }, + + /** + * @function + * @param {Element} container + */ + drawHTML: function(container, viewport) { + var element = this.element; + if (element.parentNode !== container) { + //save the source parent for later if we need it + element.prevElementParent = element.parentNode; + element.prevNextSibling = element.nextSibling; + container.appendChild(element); + + // have to set position before calculating size, fix #1116 + this.style.position = "absolute"; + // this.size is used by overlays which don't get scaled in at + // least one direction when this.checkResize is set to false. + this.size = $.getElementSize(element); + } + + var positionAndSize = this._getOverlayPositionAndSize(viewport); + + var position = positionAndSize.position; + var size = this.size = positionAndSize.size; + var rotate = positionAndSize.rotate; + + // call the onDraw callback if it exists to allow one to overwrite + // the drawing/positioning/sizing of the overlay + if (this.onDraw) { + this.onDraw(position, size, this.element); + } else { + var style = this.style; + style.left = position.x + "px"; + style.top = position.y + "px"; + if (this.width !== null) { + style.width = size.x + "px"; + } + if (this.height !== null) { + style.height = size.y + "px"; + } + var transformOriginProp = $.getCssPropertyWithVendorPrefix( + 'transformOrigin'); + var transformProp = $.getCssPropertyWithVendorPrefix( + 'transform'); + if (transformOriginProp && transformProp) { + if (rotate) { + style[transformOriginProp] = this._getTransformOrigin(); + style[transformProp] = "rotate(" + rotate + "deg)"; + } else { + style[transformOriginProp] = ""; + style[transformProp] = ""; + } + } + + if (style.display !== 'none') { + style.display = 'block'; + } + } + }, + + // private + _getOverlayPositionAndSize: function(viewport) { + var position = viewport.pixelFromPoint(this.location, true); + var size = this._getSizeInPixels(viewport); + this.adjust(position, size); + + var rotate = 0; + if (viewport.degrees && + this.rotationMode !== $.OverlayRotationMode.NO_ROTATION) { + // BOUNDING_BOX is only valid if both directions get scaled. + // Get replaced by EXACT otherwise. + if (this.rotationMode === $.OverlayRotationMode.BOUNDING_BOX && + this.width !== null && this.height !== null) { + var rect = new $.Rect(position.x, position.y, size.x, size.y); + var boundingBox = this._getBoundingBox(rect, viewport.degrees); + position = boundingBox.getTopLeft(); + size = boundingBox.getSize(); + } else { + rotate = viewport.degrees; + } + } + + return { + position: position, + size: size, + rotate: rotate + }; + }, + + // private + _getSizeInPixels: function(viewport) { + var width = this.size.x; + var height = this.size.y; + if (this.width !== null || this.height !== null) { + var scaledSize = viewport.deltaPixelsFromPointsNoRotate( + new $.Point(this.width || 0, this.height || 0), true); + if (this.width !== null) { + width = scaledSize.x; + } + if (this.height !== null) { + height = scaledSize.y; + } + } + if (this.checkResize && + (this.width === null || this.height === null)) { + var eltSize = this.size = $.getElementSize(this.element); + if (this.width === null) { + width = eltSize.x; + } + if (this.height === null) { + height = eltSize.y; + } + } + return new $.Point(width, height); + }, + + // private + _getBoundingBox: function(rect, degrees) { + var refPoint = this._getPlacementPoint(rect); + return rect.rotate(degrees, refPoint).getBoundingBox(); + }, + + // private + _getPlacementPoint: function(rect) { + var result = new $.Point(rect.x, rect.y); + var properties = $.Placement.properties[this.placement]; + if (properties) { + if (properties.isHorizontallyCentered) { + result.x += rect.width / 2; + } else if (properties.isRight) { + result.x += rect.width; + } + if (properties.isVerticallyCentered) { + result.y += rect.height / 2; + } else if (properties.isBottom) { + result.y += rect.height; + } + } + return result; + }, + + // private + _getTransformOrigin: function() { + var result = ""; + var properties = $.Placement.properties[this.placement]; + if (!properties) { + return result; + } + if (properties.isLeft) { + result = "left"; + } else if (properties.isRight) { + result = "right"; + } + if (properties.isTop) { + result += " top"; + } else if (properties.isBottom) { + result += " bottom"; + } + return result; + }, + + /** + * Changes the overlay settings. + * @function + * @param {OpenSeadragon.Point|OpenSeadragon.Rect|Object} location + * If an object is specified, the options are the same than the constructor + * except for the element which can not be changed. + * @param {OpenSeadragon.Placement} placement + */ + update: function(location, placement) { + var options = $.isPlainObject(location) ? location : { + location: location, + placement: placement + }; + this._init({ + location: options.location || this.location, + placement: options.placement !== undefined ? + options.placement : this.placement, + onDraw: options.onDraw || this.onDraw, + checkResize: options.checkResize || this.checkResize, + width: options.width !== undefined ? options.width : this.width, + height: options.height !== undefined ? options.height : this.height, + rotationMode: options.rotationMode || this.rotationMode + }); + }, + + /** + * Returns the current bounds of the overlay in viewport coordinates + * @function + * @param {OpenSeadragon.Viewport} viewport the viewport + * @returns {OpenSeadragon.Rect} overlay bounds + */ + getBounds: function(viewport) { + $.console.assert(viewport, + 'A viewport must now be passed to Overlay.getBounds.'); + var width = this.width; + var height = this.height; + if (width === null || height === null) { + var size = viewport.deltaPointsFromPixelsNoRotate(this.size, true); + if (width === null) { + width = size.x; + } + if (height === null) { + height = size.y; + } + } + var location = this.location.clone(); + this.adjust(location, new $.Point(width, height)); + return this._adjustBoundsForRotation( + viewport, new $.Rect(location.x, location.y, width, height)); + }, + + // private + _adjustBoundsForRotation: function(viewport, bounds) { + if (!viewport || + viewport.degrees === 0 || + this.rotationMode === $.OverlayRotationMode.EXACT) { + return bounds; + } + if (this.rotationMode === $.OverlayRotationMode.BOUNDING_BOX) { + // If overlay not fully scalable, BOUNDING_BOX falls back to EXACT + if (this.width === null || this.height === null) { + return bounds; + } + // It is easier to just compute the position and size and + // convert to viewport coordinates. + var positionAndSize = this._getOverlayPositionAndSize(viewport); + return viewport.viewerElementToViewportRectangle(new $.Rect( + positionAndSize.position.x, + positionAndSize.position.y, + positionAndSize.size.x, + positionAndSize.size.y)); + } + + // NO_ROTATION case + return bounds.rotate(-viewport.degrees, + this._getPlacementPoint(bounds)); + } + }; + +}(OpenSeadragon)); + +/* + * OpenSeadragon - Drawer + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class Drawer + * @memberof OpenSeadragon + * @classdesc Handles rendering of tiles for an {@link OpenSeadragon.Viewer}. + * @param {Object} options - Options for this Drawer. + * @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this Drawer. + * @param {OpenSeadragon.Viewport} options.viewport - Reference to Viewer viewport. + * @param {Element} options.element - Parent element. + * @param {Number} [options.debugGridColor] - See debugGridColor in {@link OpenSeadragon.Options} for details. + */ +$.Drawer = function( options ) { + + $.console.assert( options.viewer, "[Drawer] options.viewer is required" ); + + //backward compatibility for positional args while prefering more + //idiomatic javascript options object as the only argument + var args = arguments; + + if( !$.isPlainObject( options ) ){ + options = { + source: args[ 0 ], // Reference to Viewer tile source. + viewport: args[ 1 ], // Reference to Viewer viewport. + element: args[ 2 ] // Parent element. + }; + } + + $.console.assert( options.viewport, "[Drawer] options.viewport is required" ); + $.console.assert( options.element, "[Drawer] options.element is required" ); + + if ( options.source ) { + $.console.error( "[Drawer] options.source is no longer accepted; use TiledImage instead" ); + } + + this.viewer = options.viewer; + this.viewport = options.viewport; + this.debugGridColor = typeof options.debugGridColor === 'string' ? [options.debugGridColor] : options.debugGridColor || $.DEFAULT_SETTINGS.debugGridColor; + if (options.opacity) { + $.console.error( "[Drawer] options.opacity is no longer accepted; set the opacity on the TiledImage instead" ); + } + + this.useCanvas = $.supportsCanvas && ( this.viewer ? this.viewer.useCanvas : true ); + /** + * The parent element of this Drawer instance, passed in when the Drawer was created. + * The parent of {@link OpenSeadragon.Drawer#canvas}. + * @member {Element} container + * @memberof OpenSeadragon.Drawer# + */ + this.container = $.getElement( options.element ); + /** + * A <canvas> element if the browser supports them, otherwise a <div> element. + * Child element of {@link OpenSeadragon.Drawer#container}. + * @member {Element} canvas + * @memberof OpenSeadragon.Drawer# + */ + this.canvas = $.makeNeutralElement( this.useCanvas ? "canvas" : "div" ); + /** + * 2d drawing context for {@link OpenSeadragon.Drawer#canvas} if it's a <canvas> element, otherwise null. + * @member {Object} context + * @memberof OpenSeadragon.Drawer# + */ + this.context = this.useCanvas ? this.canvas.getContext( "2d" ) : null; + + /** + * Sketch canvas used to temporarily draw tiles which cannot be drawn directly + * to the main canvas due to opacity. Lazily initialized. + */ + this.sketchCanvas = null; + this.sketchContext = null; + + /** + * @member {Element} element + * @memberof OpenSeadragon.Drawer# + * @deprecated Alias for {@link OpenSeadragon.Drawer#container}. + */ + this.element = this.container; + + // We force our container to ltr because our drawing math doesn't work in rtl. + // This issue only affects our canvas renderer, but we do it always for consistency. + // Note that this means overlays you want to be rtl need to be explicitly set to rtl. + this.container.dir = 'ltr'; + + // check canvas available width and height, set canvas width and height such that the canvas backing store is set to the proper pixel density + if (this.useCanvas) { + var viewportSize = this._calculateCanvasSize(); + this.canvas.width = viewportSize.x; + this.canvas.height = viewportSize.y; + } + + this.canvas.style.width = "100%"; + this.canvas.style.height = "100%"; + this.canvas.style.position = "absolute"; + $.setElementOpacity( this.canvas, this.opacity, true ); + + // explicit left-align + this.container.style.textAlign = "left"; + this.container.appendChild( this.canvas ); +}; + +/** @lends OpenSeadragon.Drawer.prototype */ +$.Drawer.prototype = { + // deprecated + addOverlay: function( element, location, placement, onDraw ) { + $.console.error("drawer.addOverlay is deprecated. Use viewer.addOverlay instead."); + this.viewer.addOverlay( element, location, placement, onDraw ); + return this; + }, + + // deprecated + updateOverlay: function( element, location, placement ) { + $.console.error("drawer.updateOverlay is deprecated. Use viewer.updateOverlay instead."); + this.viewer.updateOverlay( element, location, placement ); + return this; + }, + + // deprecated + removeOverlay: function( element ) { + $.console.error("drawer.removeOverlay is deprecated. Use viewer.removeOverlay instead."); + this.viewer.removeOverlay( element ); + return this; + }, + + // deprecated + clearOverlays: function() { + $.console.error("drawer.clearOverlays is deprecated. Use viewer.clearOverlays instead."); + this.viewer.clearOverlays(); + return this; + }, + + /** + * Set the opacity of the drawer. + * @param {Number} opacity + * @return {OpenSeadragon.Drawer} Chainable. + */ + setOpacity: function( opacity ) { + $.console.error("drawer.setOpacity is deprecated. Use tiledImage.setOpacity instead."); + var world = this.viewer.world; + for (var i = 0; i < world.getItemCount(); i++) { + world.getItemAt( i ).setOpacity( opacity ); + } + return this; + }, + + /** + * Get the opacity of the drawer. + * @returns {Number} + */ + getOpacity: function() { + $.console.error("drawer.getOpacity is deprecated. Use tiledImage.getOpacity instead."); + var world = this.viewer.world; + var maxOpacity = 0; + for (var i = 0; i < world.getItemCount(); i++) { + var opacity = world.getItemAt( i ).getOpacity(); + if ( opacity > maxOpacity ) { + maxOpacity = opacity; + } + } + return maxOpacity; + }, + + // deprecated + needsUpdate: function() { + $.console.error( "[Drawer.needsUpdate] this function is deprecated. Use World.needsDraw instead." ); + return this.viewer.world.needsDraw(); + }, + + // deprecated + numTilesLoaded: function() { + $.console.error( "[Drawer.numTilesLoaded] this function is deprecated. Use TileCache.numTilesLoaded instead." ); + return this.viewer.tileCache.numTilesLoaded(); + }, + + // deprecated + reset: function() { + $.console.error( "[Drawer.reset] this function is deprecated. Use World.resetItems instead." ); + this.viewer.world.resetItems(); + return this; + }, + + // deprecated + update: function() { + $.console.error( "[Drawer.update] this function is deprecated. Use Drawer.clear and World.draw instead." ); + this.clear(); + this.viewer.world.draw(); + return this; + }, + + /** + * @return {Boolean} True if rotation is supported. + */ + canRotate: function() { + return this.useCanvas; + }, + + /** + * Destroy the drawer (unload current loaded tiles) + */ + destroy: function() { + //force unloading of current canvas (1x1 will be gc later, trick not necessarily needed) + this.canvas.width = 1; + this.canvas.height = 1; + this.sketchCanvas = null; + this.sketchContext = null; + }, + + /** + * Clears the Drawer so it's ready to draw another frame. + */ + clear: function() { + this.canvas.innerHTML = ""; + if ( this.useCanvas ) { + var viewportSize = this._calculateCanvasSize(); + if( this.canvas.width != viewportSize.x || + this.canvas.height != viewportSize.y ) { + this.canvas.width = viewportSize.x; + this.canvas.height = viewportSize.y; + if ( this.sketchCanvas !== null ) { + var sketchCanvasSize = this._calculateSketchCanvasSize(); + this.sketchCanvas.width = sketchCanvasSize.x; + this.sketchCanvas.height = sketchCanvasSize.y; + } + } + this._clear(); + } + }, + + _clear: function (useSketch, bounds) { + if (!this.useCanvas) { + return; + } + var context = this._getContext(useSketch); + if (bounds) { + context.clearRect(bounds.x, bounds.y, bounds.width, bounds.height); + } else { + var canvas = context.canvas; + context.clearRect(0, 0, canvas.width, canvas.height); + } + }, + + /** + * Scale from OpenSeadragon viewer rectangle to drawer rectangle + * (ignoring rotation) + * @param {OpenSeadragon.Rect} rectangle - The rectangle in viewport coordinate system. + * @return {OpenSeadragon.Rect} Rectangle in drawer coordinate system. + */ + viewportToDrawerRectangle: function(rectangle) { + var topLeft = this.viewport.pixelFromPointNoRotate(rectangle.getTopLeft(), true); + var size = this.viewport.deltaPixelsFromPointsNoRotate(rectangle.getSize(), true); + + return new $.Rect( + topLeft.x * $.pixelDensityRatio, + topLeft.y * $.pixelDensityRatio, + size.x * $.pixelDensityRatio, + size.y * $.pixelDensityRatio + ); + }, + + /** + * Draws the given tile. + * @param {OpenSeadragon.Tile} tile - The tile to draw. + * @param {Function} drawingHandler - Method for firing the drawing event if using canvas. + * drawingHandler({context, tile, rendered}) + * @param {Boolean} useSketch - Whether to use the sketch canvas or not. + * where rendered is the context with the pre-drawn image. + * @param {Float} [scale=1] - Apply a scale to tile position and size. Defaults to 1. + * @param {OpenSeadragon.Point} [translate] A translation vector to offset tile position + */ + drawTile: function(tile, drawingHandler, useSketch, scale, translate) { + $.console.assert(tile, '[Drawer.drawTile] tile is required'); + $.console.assert(drawingHandler, '[Drawer.drawTile] drawingHandler is required'); + + if (this.useCanvas) { + var context = this._getContext(useSketch); + scale = scale || 1; + tile.drawCanvas(context, drawingHandler, scale, translate); + } else { + tile.drawHTML( this.canvas ); + } + }, + + _getContext: function( useSketch ) { + var context = this.context; + if ( useSketch ) { + if (this.sketchCanvas === null) { + this.sketchCanvas = document.createElement( "canvas" ); + var sketchCanvasSize = this._calculateSketchCanvasSize(); + this.sketchCanvas.width = sketchCanvasSize.x; + this.sketchCanvas.height = sketchCanvasSize.y; + this.sketchContext = this.sketchCanvas.getContext( "2d" ); + + // If the viewport is not currently rotated, the sketchCanvas + // will have the same size as the main canvas. However, if + // the viewport get rotated later on, we will need to resize it. + if (this.viewport.getRotation() === 0) { + var self = this; + this.viewer.addHandler('rotate', function resizeSketchCanvas() { + if (self.viewport.getRotation() === 0) { + return; + } + self.viewer.removeHandler('rotate', resizeSketchCanvas); + var sketchCanvasSize = self._calculateSketchCanvasSize(); + self.sketchCanvas.width = sketchCanvasSize.x; + self.sketchCanvas.height = sketchCanvasSize.y; + }); + } + } + context = this.sketchContext; + } + return context; + }, + + // private + saveContext: function( useSketch ) { + if (!this.useCanvas) { + return; + } + + this._getContext( useSketch ).save(); + }, + + // private + restoreContext: function( useSketch ) { + if (!this.useCanvas) { + return; + } + + this._getContext( useSketch ).restore(); + }, + + // private + setClip: function(rect, useSketch) { + if (!this.useCanvas) { + return; + } + + var context = this._getContext( useSketch ); + context.beginPath(); + context.rect(rect.x, rect.y, rect.width, rect.height); + context.clip(); + }, + + // private + drawRectangle: function(rect, fillStyle, useSketch) { + if (!this.useCanvas) { + return; + } + + var context = this._getContext( useSketch ); + context.save(); + context.fillStyle = fillStyle; + context.fillRect(rect.x, rect.y, rect.width, rect.height); + context.restore(); + }, + + /** + * Blends the sketch canvas in the main canvas. + * @param {Object} options The options + * @param {Float} options.opacity The opacity of the blending. + * @param {Float} [options.scale=1] The scale at which tiles were drawn on + * the sketch. Default is 1. + * Use scale to draw at a lower scale and then enlarge onto the main canvas. + * @param {OpenSeadragon.Point} [options.translate] A translation vector + * that was used to draw the tiles + * @param {String} [options.compositeOperation] - How the image is + * composited onto other images; see compositeOperation in + * {@link OpenSeadragon.Options} for possible values. + * @param {OpenSeadragon.Rect} [options.bounds] The part of the sketch + * canvas to blend in the main canvas. If specified, options.scale and + * options.translate get ignored. + */ + blendSketch: function(opacity, scale, translate, compositeOperation) { + var options = opacity; + if (!$.isPlainObject(options)) { + options = { + opacity: opacity, + scale: scale, + translate: translate, + compositeOperation: compositeOperation + }; + } + if (!this.useCanvas || !this.sketchCanvas) { + return; + } + opacity = options.opacity; + compositeOperation = options.compositeOperation; + var bounds = options.bounds; + + this.context.save(); + this.context.globalAlpha = opacity; + if (compositeOperation) { + this.context.globalCompositeOperation = compositeOperation; + } + if (bounds) { + // Internet Explorer, Microsoft Edge, and Safari have problems + // when you call context.drawImage with negative x or y + // or x + width or y + height greater than the canvas width or height respectively. + if (bounds.x < 0) { + bounds.width += bounds.x; + bounds.x = 0; + } + if (bounds.x + bounds.width > this.canvas.width) { + bounds.width = this.canvas.width - bounds.x; + } + if (bounds.y < 0) { + bounds.height += bounds.y; + bounds.y = 0; + } + if (bounds.y + bounds.height > this.canvas.height) { + bounds.height = this.canvas.height - bounds.y; + } + + this.context.drawImage( + this.sketchCanvas, + bounds.x, + bounds.y, + bounds.width, + bounds.height, + bounds.x, + bounds.y, + bounds.width, + bounds.height + ); + } else { + scale = options.scale || 1; + translate = options.translate; + var position = translate instanceof $.Point ? + translate : new $.Point(0, 0); + + var widthExt = 0; + var heightExt = 0; + if (translate) { + var widthDiff = this.sketchCanvas.width - this.canvas.width; + var heightDiff = this.sketchCanvas.height - this.canvas.height; + widthExt = Math.round(widthDiff / 2); + heightExt = Math.round(heightDiff / 2); + } + this.context.drawImage( + this.sketchCanvas, + position.x - widthExt * scale, + position.y - heightExt * scale, + (this.canvas.width + 2 * widthExt) * scale, + (this.canvas.height + 2 * heightExt) * scale, + -widthExt, + -heightExt, + this.canvas.width + 2 * widthExt, + this.canvas.height + 2 * heightExt + ); + } + this.context.restore(); + }, + + // private + drawDebugInfo: function(tile, count, i, tiledImage) { + if ( !this.useCanvas ) { + return; + } + + var colorIndex = this.viewer.world.getIndexOfItem(tiledImage) % this.debugGridColor.length; + var context = this.context; + context.save(); + context.lineWidth = 2 * $.pixelDensityRatio; + context.font = 'small-caps bold ' + (13 * $.pixelDensityRatio) + 'px arial'; + context.strokeStyle = this.debugGridColor[colorIndex]; + context.fillStyle = this.debugGridColor[colorIndex]; + + if ( this.viewport.degrees !== 0 ) { + this._offsetForRotation({degrees: this.viewport.degrees}); + } + if (tiledImage.getRotation(true) % 360 !== 0) { + this._offsetForRotation({ + degrees: tiledImage.getRotation(true), + point: tiledImage.viewport.pixelFromPointNoRotate( + tiledImage._getRotationPoint(true), true) + }); + } + + context.strokeRect( + tile.position.x * $.pixelDensityRatio, + tile.position.y * $.pixelDensityRatio, + tile.size.x * $.pixelDensityRatio, + tile.size.y * $.pixelDensityRatio + ); + + var tileCenterX = (tile.position.x + (tile.size.x / 2)) * $.pixelDensityRatio; + var tileCenterY = (tile.position.y + (tile.size.y / 2)) * $.pixelDensityRatio; + + // Rotate the text the right way around. + context.translate( tileCenterX, tileCenterY ); + context.rotate( Math.PI / 180 * -this.viewport.degrees ); + context.translate( -tileCenterX, -tileCenterY ); + + if( tile.x === 0 && tile.y === 0 ){ + context.fillText( + "Zoom: " + this.viewport.getZoom(), + tile.position.x * $.pixelDensityRatio, + (tile.position.y - 30) * $.pixelDensityRatio + ); + context.fillText( + "Pan: " + this.viewport.getBounds().toString(), + tile.position.x * $.pixelDensityRatio, + (tile.position.y - 20) * $.pixelDensityRatio + ); + } + context.fillText( + "Level: " + tile.level, + (tile.position.x + 10) * $.pixelDensityRatio, + (tile.position.y + 20) * $.pixelDensityRatio + ); + context.fillText( + "Column: " + tile.x, + (tile.position.x + 10) * $.pixelDensityRatio, + (tile.position.y + 30) * $.pixelDensityRatio + ); + context.fillText( + "Row: " + tile.y, + (tile.position.x + 10) * $.pixelDensityRatio, + (tile.position.y + 40) * $.pixelDensityRatio + ); + context.fillText( + "Order: " + i + " of " + count, + (tile.position.x + 10) * $.pixelDensityRatio, + (tile.position.y + 50) * $.pixelDensityRatio + ); + context.fillText( + "Size: " + tile.size.toString(), + (tile.position.x + 10) * $.pixelDensityRatio, + (tile.position.y + 60) * $.pixelDensityRatio + ); + context.fillText( + "Position: " + tile.position.toString(), + (tile.position.x + 10) * $.pixelDensityRatio, + (tile.position.y + 70) * $.pixelDensityRatio + ); + + if ( this.viewport.degrees !== 0 ) { + this._restoreRotationChanges(); + } + if (tiledImage.getRotation(true) % 360 !== 0) { + this._restoreRotationChanges(); + } + context.restore(); + }, + + // private + debugRect: function(rect) { + if ( this.useCanvas ) { + var context = this.context; + context.save(); + context.lineWidth = 2 * $.pixelDensityRatio; + context.strokeStyle = this.debugGridColor[0]; + context.fillStyle = this.debugGridColor[0]; + + context.strokeRect( + rect.x * $.pixelDensityRatio, + rect.y * $.pixelDensityRatio, + rect.width * $.pixelDensityRatio, + rect.height * $.pixelDensityRatio + ); + + context.restore(); + } + }, + + /** + * Get the canvas size + * @param {Boolean} sketch If set to true return the size of the sketch canvas + * @returns {OpenSeadragon.Point} The size of the canvas + */ + getCanvasSize: function(sketch) { + var canvas = this._getContext(sketch).canvas; + return new $.Point(canvas.width, canvas.height); + }, + + getCanvasCenter: function() { + return new $.Point(this.canvas.width / 2, this.canvas.height / 2); + }, + + // private + _offsetForRotation: function(options) { + var point = options.point ? + options.point.times($.pixelDensityRatio) : + this.getCanvasCenter(); + + var context = this._getContext(options.useSketch); + context.save(); + + context.translate(point.x, point.y); + context.rotate(Math.PI / 180 * options.degrees); + context.translate(-point.x, -point.y); + }, + + // private + _restoreRotationChanges: function(useSketch) { + var context = this._getContext(useSketch); + context.restore(); + }, + + // private + _calculateCanvasSize: function() { + var pixelDensityRatio = $.pixelDensityRatio; + var viewportSize = this.viewport.getContainerSize(); + return { + x: viewportSize.x * pixelDensityRatio, + y: viewportSize.y * pixelDensityRatio + }; + }, + + // private + _calculateSketchCanvasSize: function() { + var canvasSize = this._calculateCanvasSize(); + if (this.viewport.getRotation() === 0) { + return canvasSize; + } + // If the viewport is rotated, we need a larger sketch canvas in order + // to support edge smoothing. + var sketchCanvasSize = Math.ceil(Math.sqrt( + canvasSize.x * canvasSize.x + + canvasSize.y * canvasSize.y)); + return { + x: sketchCanvasSize, + y: sketchCanvasSize + }; + } +}; + +}( OpenSeadragon )); + +/* + * OpenSeadragon - Viewport + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + + +/** + * @class Viewport + * @memberof OpenSeadragon + * @classdesc Handles coordinate-related functionality (zoom, pan, rotation, etc.) + * for an {@link OpenSeadragon.Viewer}. + * @param {Object} options - Options for this Viewport. + * @param {Object} [options.margins] - See viewportMargins in {@link OpenSeadragon.Options}. + * @param {Number} [options.springStiffness] - See springStiffness in {@link OpenSeadragon.Options}. + * @param {Number} [options.animationTime] - See animationTime in {@link OpenSeadragon.Options}. + * @param {Number} [options.minZoomImageRatio] - See minZoomImageRatio in {@link OpenSeadragon.Options}. + * @param {Number} [options.maxZoomPixelRatio] - See maxZoomPixelRatio in {@link OpenSeadragon.Options}. + * @param {Number} [options.visibilityRatio] - See visibilityRatio in {@link OpenSeadragon.Options}. + * @param {Boolean} [options.wrapHorizontal] - See wrapHorizontal in {@link OpenSeadragon.Options}. + * @param {Boolean} [options.wrapVertical] - See wrapVertical in {@link OpenSeadragon.Options}. + * @param {Number} [options.defaultZoomLevel] - See defaultZoomLevel in {@link OpenSeadragon.Options}. + * @param {Number} [options.minZoomLevel] - See minZoomLevel in {@link OpenSeadragon.Options}. + * @param {Number} [options.maxZoomLevel] - See maxZoomLevel in {@link OpenSeadragon.Options}. + * @param {Number} [options.degrees] - See degrees in {@link OpenSeadragon.Options}. + * @param {Boolean} [options.homeFillsViewer] - See homeFillsViewer in {@link OpenSeadragon.Options}. + */ +$.Viewport = function( options ) { + + //backward compatibility for positional args while prefering more + //idiomatic javascript options object as the only argument + var args = arguments; + if (args.length && args[0] instanceof $.Point) { + options = { + containerSize: args[0], + contentSize: args[1], + config: args[2] + }; + } + + //options.config and the general config argument are deprecated + //in favor of the more direct specification of optional settings + //being passed directly on the options object + if ( options.config ){ + $.extend( true, options, options.config ); + delete options.config; + } + + this._margins = $.extend({ + left: 0, + top: 0, + right: 0, + bottom: 0 + }, options.margins || {}); + + delete options.margins; + + $.extend( true, this, { + + //required settings + containerSize: null, + contentSize: null, + + //internal state properties + zoomPoint: null, + viewer: null, + + //configurable options + springStiffness: $.DEFAULT_SETTINGS.springStiffness, + animationTime: $.DEFAULT_SETTINGS.animationTime, + minZoomImageRatio: $.DEFAULT_SETTINGS.minZoomImageRatio, + maxZoomPixelRatio: $.DEFAULT_SETTINGS.maxZoomPixelRatio, + visibilityRatio: $.DEFAULT_SETTINGS.visibilityRatio, + wrapHorizontal: $.DEFAULT_SETTINGS.wrapHorizontal, + wrapVertical: $.DEFAULT_SETTINGS.wrapVertical, + defaultZoomLevel: $.DEFAULT_SETTINGS.defaultZoomLevel, + minZoomLevel: $.DEFAULT_SETTINGS.minZoomLevel, + maxZoomLevel: $.DEFAULT_SETTINGS.maxZoomLevel, + degrees: $.DEFAULT_SETTINGS.degrees, + homeFillsViewer: $.DEFAULT_SETTINGS.homeFillsViewer + + }, options ); + + this._updateContainerInnerSize(); + + this.centerSpringX = new $.Spring({ + initial: 0, + springStiffness: this.springStiffness, + animationTime: this.animationTime + }); + this.centerSpringY = new $.Spring({ + initial: 0, + springStiffness: this.springStiffness, + animationTime: this.animationTime + }); + this.zoomSpring = new $.Spring({ + exponential: true, + initial: 1, + springStiffness: this.springStiffness, + animationTime: this.animationTime + }); + + this._oldCenterX = this.centerSpringX.current.value; + this._oldCenterY = this.centerSpringY.current.value; + this._oldZoom = this.zoomSpring.current.value; + + this._setContentBounds(new $.Rect(0, 0, 1, 1), 1); + + this.goHome(true); + this.update(); +}; + +/** @lends OpenSeadragon.Viewport.prototype */ +$.Viewport.prototype = { + /** + * Updates the viewport's home bounds and constraints for the given content size. + * @function + * @param {OpenSeadragon.Point} contentSize - size of the content in content units + * @return {OpenSeadragon.Viewport} Chainable. + * @fires OpenSeadragon.Viewer.event:reset-size + */ + resetContentSize: function(contentSize) { + $.console.assert(contentSize, "[Viewport.resetContentSize] contentSize is required"); + $.console.assert(contentSize instanceof $.Point, "[Viewport.resetContentSize] contentSize must be an OpenSeadragon.Point"); + $.console.assert(contentSize.x > 0, "[Viewport.resetContentSize] contentSize.x must be greater than 0"); + $.console.assert(contentSize.y > 0, "[Viewport.resetContentSize] contentSize.y must be greater than 0"); + + this._setContentBounds(new $.Rect(0, 0, 1, contentSize.y / contentSize.x), contentSize.x); + return this; + }, + + // deprecated + setHomeBounds: function(bounds, contentFactor) { + $.console.error("[Viewport.setHomeBounds] this function is deprecated; The content bounds should not be set manually."); + this._setContentBounds(bounds, contentFactor); + }, + + // Set the viewport's content bounds + // @param {OpenSeadragon.Rect} bounds - the new bounds in viewport coordinates + // without rotation + // @param {Number} contentFactor - how many content units per viewport unit + // @fires OpenSeadragon.Viewer.event:reset-size + // @private + _setContentBounds: function(bounds, contentFactor) { + $.console.assert(bounds, "[Viewport._setContentBounds] bounds is required"); + $.console.assert(bounds instanceof $.Rect, "[Viewport._setContentBounds] bounds must be an OpenSeadragon.Rect"); + $.console.assert(bounds.width > 0, "[Viewport._setContentBounds] bounds.width must be greater than 0"); + $.console.assert(bounds.height > 0, "[Viewport._setContentBounds] bounds.height must be greater than 0"); + + this._contentBoundsNoRotate = bounds.clone(); + this._contentSizeNoRotate = this._contentBoundsNoRotate.getSize().times( + contentFactor); + + this._contentBounds = bounds.rotate(this.degrees).getBoundingBox(); + this._contentSize = this._contentBounds.getSize().times(contentFactor); + this._contentAspectRatio = this._contentSize.x / this._contentSize.y; + + if (this.viewer) { + /** + * Raised when the viewer's content size or home bounds are reset + * (see {@link OpenSeadragon.Viewport#resetContentSize}). + * + * @event reset-size + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.Point} contentSize + * @property {OpenSeadragon.Rect} contentBounds - Content bounds. + * @property {OpenSeadragon.Rect} homeBounds - Content bounds. + * Deprecated use contentBounds instead. + * @property {Number} contentFactor + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.viewer.raiseEvent('reset-size', { + contentSize: this._contentSizeNoRotate.clone(), + contentFactor: contentFactor, + homeBounds: this._contentBoundsNoRotate.clone(), + contentBounds: this._contentBounds.clone() + }); + } + }, + + /** + * Returns the home zoom in "viewport zoom" value. + * @function + * @returns {Number} The home zoom in "viewport zoom". + */ + getHomeZoom: function() { + if (this.defaultZoomLevel) { + return this.defaultZoomLevel; + } + + var aspectFactor = this._contentAspectRatio / this.getAspectRatio(); + var output; + if (this.homeFillsViewer) { // fill the viewer and clip the image + output = aspectFactor >= 1 ? aspectFactor : 1; + } else { + output = aspectFactor >= 1 ? 1 : aspectFactor; + } + + return output / this._contentBounds.width; + }, + + /** + * Returns the home bounds in viewport coordinates. + * @function + * @returns {OpenSeadragon.Rect} The home bounds in vewport coordinates. + */ + getHomeBounds: function() { + return this.getHomeBoundsNoRotate().rotate(-this.getRotation()); + }, + + /** + * Returns the home bounds in viewport coordinates. + * This method ignores the viewport rotation. Use + * {@link OpenSeadragon.Viewport#getHomeBounds} to take it into account. + * @function + * @returns {OpenSeadragon.Rect} The home bounds in vewport coordinates. + */ + getHomeBoundsNoRotate: function() { + var center = this._contentBounds.getCenter(); + var width = 1.0 / this.getHomeZoom(); + var height = width / this.getAspectRatio(); + + return new $.Rect( + center.x - (width / 2.0), + center.y - (height / 2.0), + width, + height + ); + }, + + /** + * @function + * @param {Boolean} immediately + * @fires OpenSeadragon.Viewer.event:home + */ + goHome: function(immediately) { + if (this.viewer) { + /** + * Raised when the "home" operation occurs (see {@link OpenSeadragon.Viewport#goHome}). + * + * @event home + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {Boolean} immediately + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.viewer.raiseEvent('home', { + immediately: immediately + }); + } + return this.fitBounds(this.getHomeBounds(), immediately); + }, + + /** + * @function + */ + getMinZoom: function() { + var homeZoom = this.getHomeZoom(), + zoom = this.minZoomLevel ? + this.minZoomLevel : + this.minZoomImageRatio * homeZoom; + + return zoom; + }, + + /** + * @function + */ + getMaxZoom: function() { + var zoom = this.maxZoomLevel; + if (!zoom) { + zoom = this._contentSize.x * this.maxZoomPixelRatio / this._containerInnerSize.x; + zoom /= this._contentBounds.width; + } + + return Math.max( zoom, this.getHomeZoom() ); + }, + + /** + * @function + */ + getAspectRatio: function() { + return this._containerInnerSize.x / this._containerInnerSize.y; + }, + + /** + * @function + * @returns {OpenSeadragon.Point} The size of the container, in screen coordinates. + */ + getContainerSize: function() { + return new $.Point( + this.containerSize.x, + this.containerSize.y + ); + }, + + /** + * The margins push the "home" region in from the sides by the specified amounts. + * @function + * @returns {Object} Properties (Numbers, in screen coordinates): left, top, right, bottom. + */ + getMargins: function() { + return $.extend({}, this._margins); // Make a copy so we are not returning our original + }, + + /** + * The margins push the "home" region in from the sides by the specified amounts. + * @function + * @param {Object} margins - Properties (Numbers, in screen coordinates): left, top, right, bottom. + */ + setMargins: function(margins) { + $.console.assert($.type(margins) === 'object', '[Viewport.setMargins] margins must be an object'); + + this._margins = $.extend({ + left: 0, + top: 0, + right: 0, + bottom: 0 + }, margins); + + this._updateContainerInnerSize(); + if (this.viewer) { + this.viewer.forceRedraw(); + } + }, + + /** + * Returns the bounds of the visible area in viewport coordinates. + * @function + * @param {Boolean} current - Pass true for the current location; defaults to false (target location). + * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, in viewport coordinates. + */ + getBounds: function(current) { + return this.getBoundsNoRotate(current).rotate(-this.getRotation()); + }, + + /** + * Returns the bounds of the visible area in viewport coordinates. + * This method ignores the viewport rotation. Use + * {@link OpenSeadragon.Viewport#getBounds} to take it into account. + * @function + * @param {Boolean} current - Pass true for the current location; defaults to false (target location). + * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, in viewport coordinates. + */ + getBoundsNoRotate: function(current) { + var center = this.getCenter(current); + var width = 1.0 / this.getZoom(current); + var height = width / this.getAspectRatio(); + + return new $.Rect( + center.x - (width / 2.0), + center.y - (height / 2.0), + width, + height + ); + }, + + /** + * @function + * @param {Boolean} current - Pass true for the current location; defaults to false (target location). + * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, + * including the space taken by margins, in viewport coordinates. + */ + getBoundsWithMargins: function(current) { + return this.getBoundsNoRotateWithMargins(current).rotate( + -this.getRotation(), this.getCenter(current)); + }, + + /** + * @function + * @param {Boolean} current - Pass true for the current location; defaults to false (target location). + * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, + * including the space taken by margins, in viewport coordinates. + */ + getBoundsNoRotateWithMargins: function(current) { + var bounds = this.getBoundsNoRotate(current); + var factor = this._containerInnerSize.x * this.getZoom(current); + bounds.x -= this._margins.left / factor; + bounds.y -= this._margins.top / factor; + bounds.width += (this._margins.left + this._margins.right) / factor; + bounds.height += (this._margins.top + this._margins.bottom) / factor; + return bounds; + }, + + /** + * @function + * @param {Boolean} current - Pass true for the current location; defaults to false (target location). + */ + getCenter: function( current ) { + var centerCurrent = new $.Point( + this.centerSpringX.current.value, + this.centerSpringY.current.value + ), + centerTarget = new $.Point( + this.centerSpringX.target.value, + this.centerSpringY.target.value + ), + oldZoomPixel, + zoom, + width, + height, + bounds, + newZoomPixel, + deltaZoomPixels, + deltaZoomPoints; + + if ( current ) { + return centerCurrent; + } else if ( !this.zoomPoint ) { + return centerTarget; + } + + oldZoomPixel = this.pixelFromPoint(this.zoomPoint, true); + + zoom = this.getZoom(); + width = 1.0 / zoom; + height = width / this.getAspectRatio(); + bounds = new $.Rect( + centerCurrent.x - width / 2.0, + centerCurrent.y - height / 2.0, + width, + height + ); + + newZoomPixel = this._pixelFromPoint(this.zoomPoint, bounds); + deltaZoomPixels = newZoomPixel.minus( oldZoomPixel ); + deltaZoomPoints = deltaZoomPixels.divide( this._containerInnerSize.x * zoom ); + + return centerTarget.plus( deltaZoomPoints ); + }, + + /** + * @function + * @param {Boolean} current - Pass true for the current location; defaults to false (target location). + */ + getZoom: function( current ) { + if ( current ) { + return this.zoomSpring.current.value; + } else { + return this.zoomSpring.target.value; + } + }, + + // private + _applyZoomConstraints: function(zoom) { + return Math.max( + Math.min(zoom, this.getMaxZoom()), + this.getMinZoom()); + }, + + /** + * @function + * @private + * @param {OpenSeadragon.Rect} bounds + * @return {OpenSeadragon.Rect} constrained bounds. + */ + _applyBoundaryConstraints: function(bounds) { + var newBounds = new $.Rect( + bounds.x, + bounds.y, + bounds.width, + bounds.height); + + if (this.wrapHorizontal) { + //do nothing + } else { + var horizontalThreshold = this.visibilityRatio * newBounds.width; + var boundsRight = newBounds.x + newBounds.width; + var contentRight = this._contentBoundsNoRotate.x + this._contentBoundsNoRotate.width; + var leftDx = this._contentBoundsNoRotate.x - boundsRight + horizontalThreshold; + var rightDx = contentRight - newBounds.x - horizontalThreshold; + + if (horizontalThreshold > this._contentBoundsNoRotate.width) { + newBounds.x += (leftDx + rightDx) / 2; + } else if (rightDx < 0) { + newBounds.x += rightDx; + } else if (leftDx > 0) { + newBounds.x += leftDx; + } + } + + if (this.wrapVertical) { + //do nothing + } else { + var verticalThreshold = this.visibilityRatio * newBounds.height; + var boundsBottom = newBounds.y + newBounds.height; + var contentBottom = this._contentBoundsNoRotate.y + this._contentBoundsNoRotate.height; + var topDy = this._contentBoundsNoRotate.y - boundsBottom + verticalThreshold; + var bottomDy = contentBottom - newBounds.y - verticalThreshold; + + if (verticalThreshold > this._contentBoundsNoRotate.height) { + newBounds.y += (topDy + bottomDy) / 2; + } else if (bottomDy < 0) { + newBounds.y += bottomDy; + } else if (topDy > 0) { + newBounds.y += topDy; + } + } + + return newBounds; + }, + + /** + * @function + * @private + * @param {Boolean} [immediately=false] - whether the function that triggered this event was + * called with the "immediately" flag + */ + _raiseConstraintsEvent: function(immediately) { + if (this.viewer) { + /** + * Raised when the viewport constraints are applied (see {@link OpenSeadragon.Viewport#applyConstraints}). + * + * @event constrain + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {Boolean} immediately - whether the function that triggered this event was + * called with the "immediately" flag + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.viewer.raiseEvent( 'constrain', { + immediately: immediately + }); + } + }, + + /** + * Enforces the minZoom, maxZoom and visibilityRatio constraints by + * zooming and panning to the closest acceptable zoom and location. + * @function + * @param {Boolean} [immediately=false] + * @return {OpenSeadragon.Viewport} Chainable. + * @fires OpenSeadragon.Viewer.event:constrain + */ + applyConstraints: function(immediately) { + var actualZoom = this.getZoom(); + var constrainedZoom = this._applyZoomConstraints(actualZoom); + + if (actualZoom !== constrainedZoom) { + this.zoomTo(constrainedZoom, this.zoomPoint, immediately); + } + + var bounds = this.getBoundsNoRotate(); + var constrainedBounds = this._applyBoundaryConstraints(bounds); + this._raiseConstraintsEvent(immediately); + + if (bounds.x !== constrainedBounds.x || + bounds.y !== constrainedBounds.y || + immediately) { + this.fitBounds( + constrainedBounds.rotate(-this.getRotation()), + immediately); + } + return this; + }, + + /** + * Equivalent to {@link OpenSeadragon.Viewport#applyConstraints} + * @function + * @param {Boolean} [immediately=false] + * @return {OpenSeadragon.Viewport} Chainable. + * @fires OpenSeadragon.Viewer.event:constrain + */ + ensureVisible: function(immediately) { + return this.applyConstraints(immediately); + }, + + /** + * @function + * @private + * @param {OpenSeadragon.Rect} bounds + * @param {Object} options (immediately=false, constraints=false) + * @return {OpenSeadragon.Viewport} Chainable. + */ + _fitBounds: function(bounds, options) { + options = options || {}; + var immediately = options.immediately || false; + var constraints = options.constraints || false; + + var aspect = this.getAspectRatio(); + var center = bounds.getCenter(); + + // Compute width and height of bounding box. + var newBounds = new $.Rect( + bounds.x, + bounds.y, + bounds.width, + bounds.height, + bounds.degrees + this.getRotation()) + .getBoundingBox(); + + if (newBounds.getAspectRatio() >= aspect) { + newBounds.height = newBounds.width / aspect; + } else { + newBounds.width = newBounds.height * aspect; + } + + // Compute x and y from width, height and center position + newBounds.x = center.x - newBounds.width / 2; + newBounds.y = center.y - newBounds.height / 2; + var newZoom = 1.0 / newBounds.width; + + if (constraints) { + var newBoundsAspectRatio = newBounds.getAspectRatio(); + var newConstrainedZoom = this._applyZoomConstraints(newZoom); + + if (newZoom !== newConstrainedZoom) { + newZoom = newConstrainedZoom; + newBounds.width = 1.0 / newZoom; + newBounds.x = center.x - newBounds.width / 2; + newBounds.height = newBounds.width / newBoundsAspectRatio; + newBounds.y = center.y - newBounds.height / 2; + } + + newBounds = this._applyBoundaryConstraints(newBounds); + center = newBounds.getCenter(); + this._raiseConstraintsEvent(immediately); + } + + if (immediately) { + this.panTo(center, true); + return this.zoomTo(newZoom, null, true); + } + + this.panTo(this.getCenter(true), true); + this.zoomTo(this.getZoom(true), null, true); + + var oldBounds = this.getBounds(); + var oldZoom = this.getZoom(); + + if (oldZoom === 0 || Math.abs(newZoom / oldZoom - 1) < 0.00000001) { + this.zoomTo(newZoom, true); + return this.panTo(center, immediately); + } + + newBounds = newBounds.rotate(-this.getRotation()); + var referencePoint = newBounds.getTopLeft().times(newZoom) + .minus(oldBounds.getTopLeft().times(oldZoom)) + .divide(newZoom - oldZoom); + + return this.zoomTo(newZoom, referencePoint, immediately); + }, + + /** + * Makes the viewport zoom and pan so that the specified bounds take + * as much space as possible in the viewport. + * Note: this method ignores the constraints (minZoom, maxZoom and + * visibilityRatio). + * Use {@link OpenSeadragon.Viewport#fitBoundsWithConstraints} to enforce + * them. + * @function + * @param {OpenSeadragon.Rect} bounds + * @param {Boolean} [immediately=false] + * @return {OpenSeadragon.Viewport} Chainable. + */ + fitBounds: function(bounds, immediately) { + return this._fitBounds(bounds, { + immediately: immediately, + constraints: false + }); + }, + + /** + * Makes the viewport zoom and pan so that the specified bounds take + * as much space as possible in the viewport while enforcing the constraints + * (minZoom, maxZoom and visibilityRatio). + * Note: because this method enforces the constraints, part of the + * provided bounds may end up outside of the viewport. + * Use {@link OpenSeadragon.Viewport#fitBounds} to ignore them. + * @function + * @param {OpenSeadragon.Rect} bounds + * @param {Boolean} [immediately=false] + * @return {OpenSeadragon.Viewport} Chainable. + */ + fitBoundsWithConstraints: function(bounds, immediately) { + return this._fitBounds(bounds, { + immediately: immediately, + constraints: true + }); + }, + + /** + * Zooms so the image just fills the viewer vertically. + * @param {Boolean} immediately + * @return {OpenSeadragon.Viewport} Chainable. + */ + fitVertically: function(immediately) { + var box = new $.Rect( + this._contentBounds.x + (this._contentBounds.width / 2), + this._contentBounds.y, + 0, + this._contentBounds.height); + return this.fitBounds(box, immediately); + }, + + /** + * Zooms so the image just fills the viewer horizontally. + * @param {Boolean} immediately + * @return {OpenSeadragon.Viewport} Chainable. + */ + fitHorizontally: function(immediately) { + var box = new $.Rect( + this._contentBounds.x, + this._contentBounds.y + (this._contentBounds.height / 2), + this._contentBounds.width, + 0); + return this.fitBounds(box, immediately); + }, + + + /** + * Returns bounds taking constraints into account + * Added to improve constrained panning + * @param {Boolean} current - Pass true for the current location; defaults to false (target location). + * @return {OpenSeadragon.Viewport} Chainable. + */ + getConstrainedBounds: function(current) { + var bounds, + constrainedBounds; + + bounds = this.getBounds(current); + + constrainedBounds = this._applyBoundaryConstraints(bounds); + + return constrainedBounds; + }, + + /** + * @function + * @param {OpenSeadragon.Point} delta + * @param {Boolean} immediately + * @return {OpenSeadragon.Viewport} Chainable. + * @fires OpenSeadragon.Viewer.event:pan + */ + panBy: function( delta, immediately ) { + var center = new $.Point( + this.centerSpringX.target.value, + this.centerSpringY.target.value + ); + return this.panTo( center.plus( delta ), immediately ); + }, + + /** + * @function + * @param {OpenSeadragon.Point} center + * @param {Boolean} immediately + * @return {OpenSeadragon.Viewport} Chainable. + * @fires OpenSeadragon.Viewer.event:pan + */ + panTo: function( center, immediately ) { + if ( immediately ) { + this.centerSpringX.resetTo( center.x ); + this.centerSpringY.resetTo( center.y ); + } else { + this.centerSpringX.springTo( center.x ); + this.centerSpringY.springTo( center.y ); + } + + if( this.viewer ){ + /** + * Raised when the viewport is panned (see {@link OpenSeadragon.Viewport#panBy} and {@link OpenSeadragon.Viewport#panTo}). + * + * @event pan + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.Point} center + * @property {Boolean} immediately + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.viewer.raiseEvent( 'pan', { + center: center, + immediately: immediately + }); + } + + return this; + }, + + /** + * @function + * @return {OpenSeadragon.Viewport} Chainable. + * @fires OpenSeadragon.Viewer.event:zoom + */ + zoomBy: function(factor, refPoint, immediately) { + return this.zoomTo( + this.zoomSpring.target.value * factor, refPoint, immediately); + }, + + /** + * Zooms to the specified zoom level + * @function + * @param {Number} zoom The zoom level to zoom to. + * @param {OpenSeadragon.Point} [refPoint] The point which will stay at + * the same screen location. Defaults to the viewport center. + * @param {Boolean} [immediately=false] + * @return {OpenSeadragon.Viewport} Chainable. + * @fires OpenSeadragon.Viewer.event:zoom + */ + zoomTo: function(zoom, refPoint, immediately) { + var _this = this; + + this.zoomPoint = refPoint instanceof $.Point && + !isNaN(refPoint.x) && + !isNaN(refPoint.y) ? + refPoint : + null; + + if (immediately) { + this._adjustCenterSpringsForZoomPoint(function() { + _this.zoomSpring.resetTo(zoom); + }); + } else { + this.zoomSpring.springTo(zoom); + } + + if (this.viewer) { + /** + * Raised when the viewport zoom level changes (see {@link OpenSeadragon.Viewport#zoomBy} and {@link OpenSeadragon.Viewport#zoomTo}). + * + * @event zoom + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {Number} zoom + * @property {OpenSeadragon.Point} refPoint + * @property {Boolean} immediately + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.viewer.raiseEvent('zoom', { + zoom: zoom, + refPoint: refPoint, + immediately: immediately + }); + } + + return this; + }, + + /** + * Rotates this viewport to the angle specified. + * @function + * @return {OpenSeadragon.Viewport} Chainable. + */ + setRotation: function(degrees) { + if (!this.viewer || !this.viewer.drawer.canRotate()) { + return this; + } + + this.degrees = $.positiveModulo(degrees, 360); + this._setContentBounds( + this.viewer.world.getHomeBounds(), + this.viewer.world.getContentFactor()); + this.viewer.forceRedraw(); + + /** + * Raised when rotation has been changed. + * + * @event rotate + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Number} degrees - The number of degrees the rotation was set to. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.viewer.raiseEvent('rotate', {"degrees": degrees}); + return this; + }, + + /** + * Gets the current rotation in degrees. + * @function + * @return {Number} The current rotation in degrees. + */ + getRotation: function() { + return this.degrees; + }, + + /** + * @function + * @return {OpenSeadragon.Viewport} Chainable. + * @fires OpenSeadragon.Viewer.event:resize + */ + resize: function( newContainerSize, maintain ) { + var oldBounds = this.getBoundsNoRotate(), + newBounds = oldBounds, + widthDeltaFactor; + + this.containerSize.x = newContainerSize.x; + this.containerSize.y = newContainerSize.y; + + this._updateContainerInnerSize(); + + if ( maintain ) { + // TODO: widthDeltaFactor will always be 1; probably not what's intended + widthDeltaFactor = newContainerSize.x / this.containerSize.x; + newBounds.width = oldBounds.width * widthDeltaFactor; + newBounds.height = newBounds.width / this.getAspectRatio(); + } + + if( this.viewer ){ + /** + * Raised when the viewer is resized (see {@link OpenSeadragon.Viewport#resize}). + * + * @event resize + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.Point} newContainerSize + * @property {Boolean} maintain + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.viewer.raiseEvent( 'resize', { + newContainerSize: newContainerSize, + maintain: maintain + }); + } + + return this.fitBounds( newBounds, true ); + }, + + // private + _updateContainerInnerSize: function() { + this._containerInnerSize = new $.Point( + Math.max(1, this.containerSize.x - (this._margins.left + this._margins.right)), + Math.max(1, this.containerSize.y - (this._margins.top + this._margins.bottom)) + ); + }, + + /** + * Update the zoom and center (X and Y) springs. + * @function + * @returns {Boolean} True if any change has been made, false otherwise. + */ + update: function() { + var _this = this; + this._adjustCenterSpringsForZoomPoint(function() { + _this.zoomSpring.update(); + }); + + this.centerSpringX.update(); + this.centerSpringY.update(); + + var changed = this.centerSpringX.current.value !== this._oldCenterX || + this.centerSpringY.current.value !== this._oldCenterY || + this.zoomSpring.current.value !== this._oldZoom; + + this._oldCenterX = this.centerSpringX.current.value; + this._oldCenterY = this.centerSpringY.current.value; + this._oldZoom = this.zoomSpring.current.value; + + return changed; + }, + + _adjustCenterSpringsForZoomPoint: function(zoomSpringHandler) { + if (this.zoomPoint) { + var oldZoomPixel = this.pixelFromPoint(this.zoomPoint, true); + zoomSpringHandler(); + var newZoomPixel = this.pixelFromPoint(this.zoomPoint, true); + + var deltaZoomPixels = newZoomPixel.minus(oldZoomPixel); + var deltaZoomPoints = this.deltaPointsFromPixels( + deltaZoomPixels, true); + + this.centerSpringX.shiftBy(deltaZoomPoints.x); + this.centerSpringY.shiftBy(deltaZoomPoints.y); + + if (this.zoomSpring.isAtTargetValue()) { + this.zoomPoint = null; + } + } else { + zoomSpringHandler(); + } + }, + + /** + * Convert a delta (translation vector) from viewport coordinates to pixels + * coordinates. This method does not take rotation into account. + * Consider using deltaPixelsFromPoints if you need to account for rotation. + * @param {OpenSeadragon.Point} deltaPoints - The translation vector to convert. + * @param {Boolean} [current=false] - Pass true for the current location; + * defaults to false (target location). + * @returns {OpenSeadragon.Point} + */ + deltaPixelsFromPointsNoRotate: function(deltaPoints, current) { + return deltaPoints.times( + this._containerInnerSize.x * this.getZoom(current) + ); + }, + + /** + * Convert a delta (translation vector) from viewport coordinates to pixels + * coordinates. + * @param {OpenSeadragon.Point} deltaPoints - The translation vector to convert. + * @param {Boolean} [current=false] - Pass true for the current location; + * defaults to false (target location). + * @returns {OpenSeadragon.Point} + */ + deltaPixelsFromPoints: function(deltaPoints, current) { + return this.deltaPixelsFromPointsNoRotate( + deltaPoints.rotate(this.getRotation()), + current); + }, + + /** + * Convert a delta (translation vector) from pixels coordinates to viewport + * coordinates. This method does not take rotation into account. + * Consider using deltaPointsFromPixels if you need to account for rotation. + * @param {OpenSeadragon.Point} deltaPixels - The translation vector to convert. + * @param {Boolean} [current=false] - Pass true for the current location; + * defaults to false (target location). + * @returns {OpenSeadragon.Point} + */ + deltaPointsFromPixelsNoRotate: function(deltaPixels, current) { + return deltaPixels.divide( + this._containerInnerSize.x * this.getZoom(current) + ); + }, + + /** + * Convert a delta (translation vector) from pixels coordinates to viewport + * coordinates. + * @param {OpenSeadragon.Point} deltaPixels - The translation vector to convert. + * @param {Boolean} [current=false] - Pass true for the current location; + * defaults to false (target location). + * @returns {OpenSeadragon.Point} + */ + deltaPointsFromPixels: function(deltaPixels, current) { + return this.deltaPointsFromPixelsNoRotate(deltaPixels, current) + .rotate(-this.getRotation()); + }, + + /** + * Convert viewport coordinates to pixels coordinates. + * This method does not take rotation into account. + * Consider using pixelFromPoint if you need to account for rotation. + * @param {OpenSeadragon.Point} point the viewport coordinates + * @param {Boolean} [current=false] - Pass true for the current location; + * defaults to false (target location). + * @returns {OpenSeadragon.Point} + */ + pixelFromPointNoRotate: function(point, current) { + return this._pixelFromPointNoRotate( + point, this.getBoundsNoRotate(current)); + }, + + /** + * Convert viewport coordinates to pixel coordinates. + * @param {OpenSeadragon.Point} point the viewport coordinates + * @param {Boolean} [current=false] - Pass true for the current location; + * defaults to false (target location). + * @returns {OpenSeadragon.Point} + */ + pixelFromPoint: function(point, current) { + return this._pixelFromPoint(point, this.getBoundsNoRotate(current)); + }, + + // private + _pixelFromPointNoRotate: function(point, bounds) { + return point.minus( + bounds.getTopLeft() + ).times( + this._containerInnerSize.x / bounds.width + ).plus( + new $.Point(this._margins.left, this._margins.top) + ); + }, + + // private + _pixelFromPoint: function(point, bounds) { + return this._pixelFromPointNoRotate( + point.rotate(this.getRotation(), this.getCenter(true)), + bounds); + }, + + /** + * Convert pixel coordinates to viewport coordinates. + * This method does not take rotation into account. + * Consider using pointFromPixel if you need to account for rotation. + * @param {OpenSeadragon.Point} pixel Pixel coordinates + * @param {Boolean} [current=false] - Pass true for the current location; + * defaults to false (target location). + * @returns {OpenSeadragon.Point} + */ + pointFromPixelNoRotate: function(pixel, current) { + var bounds = this.getBoundsNoRotate(current); + return pixel.minus( + new $.Point(this._margins.left, this._margins.top) + ).divide( + this._containerInnerSize.x / bounds.width + ).plus( + bounds.getTopLeft() + ); + }, + + /** + * Convert pixel coordinates to viewport coordinates. + * @param {OpenSeadragon.Point} pixel Pixel coordinates + * @param {Boolean} [current=false] - Pass true for the current location; + * defaults to false (target location). + * @returns {OpenSeadragon.Point} + */ + pointFromPixel: function(pixel, current) { + return this.pointFromPixelNoRotate(pixel, current).rotate( + -this.getRotation(), + this.getCenter(true) + ); + }, + + // private + _viewportToImageDelta: function( viewerX, viewerY ) { + var scale = this._contentBoundsNoRotate.width; + return new $.Point( + viewerX * this._contentSizeNoRotate.x / scale, + viewerY * this._contentSizeNoRotate.x / scale); + }, + + /** + * Translates from OpenSeadragon viewer coordinate system to image coordinate system. + * This method can be called either by passing X,Y coordinates or an + * OpenSeadragon.Point + * Note: not accurate with multi-image; use TiledImage.viewportToImageCoordinates instead. + * @function + * @param {(OpenSeadragon.Point|Number)} viewerX either a point or the X + * coordinate in viewport coordinate system. + * @param {Number} [viewerY] Y coordinate in viewport coordinate system. + * @return {OpenSeadragon.Point} a point representing the coordinates in the image. + */ + viewportToImageCoordinates: function(viewerX, viewerY) { + if (viewerX instanceof $.Point) { + //they passed a point instead of individual components + return this.viewportToImageCoordinates(viewerX.x, viewerX.y); + } + + if (this.viewer) { + var count = this.viewer.world.getItemCount(); + if (count > 1) { + $.console.error('[Viewport.viewportToImageCoordinates] is not accurate ' + + 'with multi-image; use TiledImage.viewportToImageCoordinates instead.'); + } else if (count === 1) { + // It is better to use TiledImage.viewportToImageCoordinates + // because this._contentBoundsNoRotate can not be relied on + // with clipping. + var item = this.viewer.world.getItemAt(0); + return item.viewportToImageCoordinates(viewerX, viewerY, true); + } + } + + return this._viewportToImageDelta( + viewerX - this._contentBoundsNoRotate.x, + viewerY - this._contentBoundsNoRotate.y); + }, + + // private + _imageToViewportDelta: function( imageX, imageY ) { + var scale = this._contentBoundsNoRotate.width; + return new $.Point( + imageX / this._contentSizeNoRotate.x * scale, + imageY / this._contentSizeNoRotate.x * scale); + }, + + /** + * Translates from image coordinate system to OpenSeadragon viewer coordinate system + * This method can be called either by passing X,Y coordinates or an + * OpenSeadragon.Point + * Note: not accurate with multi-image; use TiledImage.imageToViewportCoordinates instead. + * @function + * @param {(OpenSeadragon.Point | Number)} imageX the point or the + * X coordinate in image coordinate system. + * @param {Number} [imageY] Y coordinate in image coordinate system. + * @return {OpenSeadragon.Point} a point representing the coordinates in the viewport. + */ + imageToViewportCoordinates: function(imageX, imageY) { + if (imageX instanceof $.Point) { + //they passed a point instead of individual components + return this.imageToViewportCoordinates(imageX.x, imageX.y); + } + + if (this.viewer) { + var count = this.viewer.world.getItemCount(); + if (count > 1) { + $.console.error('[Viewport.imageToViewportCoordinates] is not accurate ' + + 'with multi-image; use TiledImage.imageToViewportCoordinates instead.'); + } else if (count === 1) { + // It is better to use TiledImage.viewportToImageCoordinates + // because this._contentBoundsNoRotate can not be relied on + // with clipping. + var item = this.viewer.world.getItemAt(0); + return item.imageToViewportCoordinates(imageX, imageY, true); + } + } + + var point = this._imageToViewportDelta(imageX, imageY); + point.x += this._contentBoundsNoRotate.x; + point.y += this._contentBoundsNoRotate.y; + return point; + }, + + /** + * Translates from a rectangle which describes a portion of the image in + * pixel coordinates to OpenSeadragon viewport rectangle coordinates. + * This method can be called either by passing X,Y,width,height or an + * OpenSeadragon.Rect + * Note: not accurate with multi-image; use TiledImage.imageToViewportRectangle instead. + * @function + * @param {(OpenSeadragon.Rect | Number)} imageX the rectangle or the X + * coordinate of the top left corner of the rectangle in image coordinate system. + * @param {Number} [imageY] the Y coordinate of the top left corner of the rectangle + * in image coordinate system. + * @param {Number} [pixelWidth] the width in pixel of the rectangle. + * @param {Number} [pixelHeight] the height in pixel of the rectangle. + * @returns {OpenSeadragon.Rect} This image's bounds in viewport coordinates + */ + imageToViewportRectangle: function(imageX, imageY, pixelWidth, pixelHeight) { + var rect = imageX; + if (!(rect instanceof $.Rect)) { + //they passed individual components instead of a rectangle + rect = new $.Rect(imageX, imageY, pixelWidth, pixelHeight); + } + + if (this.viewer) { + var count = this.viewer.world.getItemCount(); + if (count > 1) { + $.console.error('[Viewport.imageToViewportRectangle] is not accurate ' + + 'with multi-image; use TiledImage.imageToViewportRectangle instead.'); + } else if (count === 1) { + // It is better to use TiledImage.imageToViewportRectangle + // because this._contentBoundsNoRotate can not be relied on + // with clipping. + var item = this.viewer.world.getItemAt(0); + return item.imageToViewportRectangle( + imageX, imageY, pixelWidth, pixelHeight, true); + } + } + + var coordA = this.imageToViewportCoordinates(rect.x, rect.y); + var coordB = this._imageToViewportDelta(rect.width, rect.height); + return new $.Rect( + coordA.x, + coordA.y, + coordB.x, + coordB.y, + rect.degrees + ); + }, + + /** + * Translates from a rectangle which describes a portion of + * the viewport in point coordinates to image rectangle coordinates. + * This method can be called either by passing X,Y,width,height or an + * OpenSeadragon.Rect + * Note: not accurate with multi-image; use TiledImage.viewportToImageRectangle instead. + * @function + * @param {(OpenSeadragon.Rect | Number)} viewerX either a rectangle or + * the X coordinate of the top left corner of the rectangle in viewport + * coordinate system. + * @param {Number} [viewerY] the Y coordinate of the top left corner of the rectangle + * in viewport coordinate system. + * @param {Number} [pointWidth] the width of the rectangle in viewport coordinate system. + * @param {Number} [pointHeight] the height of the rectangle in viewport coordinate system. + */ + viewportToImageRectangle: function(viewerX, viewerY, pointWidth, pointHeight) { + var rect = viewerX; + if (!(rect instanceof $.Rect)) { + //they passed individual components instead of a rectangle + rect = new $.Rect(viewerX, viewerY, pointWidth, pointHeight); + } + + if (this.viewer) { + var count = this.viewer.world.getItemCount(); + if (count > 1) { + $.console.error('[Viewport.viewportToImageRectangle] is not accurate ' + + 'with multi-image; use TiledImage.viewportToImageRectangle instead.'); + } else if (count === 1) { + // It is better to use TiledImage.viewportToImageCoordinates + // because this._contentBoundsNoRotate can not be relied on + // with clipping. + var item = this.viewer.world.getItemAt(0); + return item.viewportToImageRectangle( + viewerX, viewerY, pointWidth, pointHeight, true); + } + } + + var coordA = this.viewportToImageCoordinates(rect.x, rect.y); + var coordB = this._viewportToImageDelta(rect.width, rect.height); + return new $.Rect( + coordA.x, + coordA.y, + coordB.x, + coordB.y, + rect.degrees + ); + }, + + /** + * Convert pixel coordinates relative to the viewer element to image + * coordinates. + * Note: not accurate with multi-image. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + viewerElementToImageCoordinates: function( pixel ) { + var point = this.pointFromPixel( pixel, true ); + return this.viewportToImageCoordinates( point ); + }, + + /** + * Convert pixel coordinates relative to the image to + * viewer element coordinates. + * Note: not accurate with multi-image. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + imageToViewerElementCoordinates: function( pixel ) { + var point = this.imageToViewportCoordinates( pixel ); + return this.pixelFromPoint( point, true ); + }, + + /** + * Convert pixel coordinates relative to the window to image coordinates. + * Note: not accurate with multi-image. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + windowToImageCoordinates: function(pixel) { + $.console.assert(this.viewer, + "[Viewport.windowToImageCoordinates] the viewport must have a viewer."); + var viewerCoordinates = pixel.minus( + $.getElementPosition(this.viewer.element)); + return this.viewerElementToImageCoordinates(viewerCoordinates); + }, + + /** + * Convert image coordinates to pixel coordinates relative to the window. + * Note: not accurate with multi-image. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + imageToWindowCoordinates: function(pixel) { + $.console.assert(this.viewer, + "[Viewport.imageToWindowCoordinates] the viewport must have a viewer."); + var viewerCoordinates = this.imageToViewerElementCoordinates(pixel); + return viewerCoordinates.plus( + $.getElementPosition(this.viewer.element)); + }, + + /** + * Convert pixel coordinates relative to the viewer element to viewport + * coordinates. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + viewerElementToViewportCoordinates: function( pixel ) { + return this.pointFromPixel( pixel, true ); + }, + + /** + * Convert viewport coordinates to pixel coordinates relative to the + * viewer element. + * @param {OpenSeadragon.Point} point + * @returns {OpenSeadragon.Point} + */ + viewportToViewerElementCoordinates: function( point ) { + return this.pixelFromPoint( point, true ); + }, + + /** + * Convert a rectangle in pixel coordinates relative to the viewer element + * to viewport coordinates. + * @param {OpenSeadragon.Rect} rectangle the rectangle to convert + * @returns {OpenSeadragon.Rect} the converted rectangle + */ + viewerElementToViewportRectangle: function(rectangle) { + return $.Rect.fromSummits( + this.pointFromPixel(rectangle.getTopLeft(), true), + this.pointFromPixel(rectangle.getTopRight(), true), + this.pointFromPixel(rectangle.getBottomLeft(), true) + ); + }, + + /** + * Convert a rectangle in viewport coordinates to pixel coordinates relative + * to the viewer element. + * @param {OpenSeadragon.Rect} rectangle the rectangle to convert + * @returns {OpenSeadragon.Rect} the converted rectangle + */ + viewportToViewerElementRectangle: function(rectangle) { + return $.Rect.fromSummits( + this.pixelFromPoint(rectangle.getTopLeft(), true), + this.pixelFromPoint(rectangle.getTopRight(), true), + this.pixelFromPoint(rectangle.getBottomLeft(), true) + ); + }, + + /** + * Convert pixel coordinates relative to the window to viewport coordinates. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + windowToViewportCoordinates: function(pixel) { + $.console.assert(this.viewer, + "[Viewport.windowToViewportCoordinates] the viewport must have a viewer."); + var viewerCoordinates = pixel.minus( + $.getElementPosition(this.viewer.element)); + return this.viewerElementToViewportCoordinates(viewerCoordinates); + }, + + /** + * Convert viewport coordinates to pixel coordinates relative to the window. + * @param {OpenSeadragon.Point} point + * @returns {OpenSeadragon.Point} + */ + viewportToWindowCoordinates: function(point) { + $.console.assert(this.viewer, + "[Viewport.viewportToWindowCoordinates] the viewport must have a viewer."); + var viewerCoordinates = this.viewportToViewerElementCoordinates(point); + return viewerCoordinates.plus( + $.getElementPosition(this.viewer.element)); + }, + + /** + * Convert a viewport zoom to an image zoom. + * Image zoom: ratio of the original image size to displayed image size. + * 1 means original image size, 0.5 half size... + * Viewport zoom: ratio of the displayed image's width to viewport's width. + * 1 means identical width, 2 means image's width is twice the viewport's width... + * Note: not accurate with multi-image. + * @function + * @param {Number} viewportZoom The viewport zoom + * target zoom. + * @returns {Number} imageZoom The image zoom + */ + viewportToImageZoom: function(viewportZoom) { + if (this.viewer) { + var count = this.viewer.world.getItemCount(); + if (count > 1) { + $.console.error('[Viewport.viewportToImageZoom] is not ' + + 'accurate with multi-image.'); + } else if (count === 1) { + // It is better to use TiledImage.viewportToImageZoom + // because this._contentBoundsNoRotate can not be relied on + // with clipping. + var item = this.viewer.world.getItemAt(0); + return item.viewportToImageZoom(viewportZoom); + } + } + + var imageWidth = this._contentSizeNoRotate.x; + var containerWidth = this._containerInnerSize.x; + var scale = this._contentBoundsNoRotate.width; + var viewportToImageZoomRatio = (containerWidth / imageWidth) * scale; + return viewportZoom * viewportToImageZoomRatio; + }, + + /** + * Convert an image zoom to a viewport zoom. + * Image zoom: ratio of the original image size to displayed image size. + * 1 means original image size, 0.5 half size... + * Viewport zoom: ratio of the displayed image's width to viewport's width. + * 1 means identical width, 2 means image's width is twice the viewport's width... + * Note: not accurate with multi-image. + * @function + * @param {Number} imageZoom The image zoom + * target zoom. + * @returns {Number} viewportZoom The viewport zoom + */ + imageToViewportZoom: function(imageZoom) { + if (this.viewer) { + var count = this.viewer.world.getItemCount(); + if (count > 1) { + $.console.error('[Viewport.imageToViewportZoom] is not accurate ' + + 'with multi-image.'); + } else if (count === 1) { + // It is better to use TiledImage.imageToViewportZoom + // because this._contentBoundsNoRotate can not be relied on + // with clipping. + var item = this.viewer.world.getItemAt(0); + return item.imageToViewportZoom(imageZoom); + } + } + + var imageWidth = this._contentSizeNoRotate.x; + var containerWidth = this._containerInnerSize.x; + var scale = this._contentBoundsNoRotate.width; + var viewportToImageZoomRatio = (imageWidth / containerWidth) / scale; + return imageZoom * viewportToImageZoomRatio; + } +}; + +}( OpenSeadragon )); + +/* + * OpenSeadragon - TiledImage + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * You shouldn't have to create a TiledImage directly; use {@link OpenSeadragon.Viewer#open} + * or {@link OpenSeadragon.Viewer#addTiledImage} instead. + * @class TiledImage + * @memberof OpenSeadragon + * @extends OpenSeadragon.EventSource + * @classdesc Handles rendering of tiles for an {@link OpenSeadragon.Viewer}. + * A new instance is created for each TileSource opened. + * @param {Object} options - Configuration for this TiledImage. + * @param {OpenSeadragon.TileSource} options.source - The TileSource that defines this TiledImage. + * @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this TiledImage. + * @param {OpenSeadragon.TileCache} options.tileCache - The TileCache for this TiledImage to use. + * @param {OpenSeadragon.Drawer} options.drawer - The Drawer for this TiledImage to draw onto. + * @param {OpenSeadragon.ImageLoader} options.imageLoader - The ImageLoader for this TiledImage to use. + * @param {Number} [options.x=0] - Left position, in viewport coordinates. + * @param {Number} [options.y=0] - Top position, in viewport coordinates. + * @param {Number} [options.width=1] - Width, in viewport coordinates. + * @param {Number} [options.height] - Height, in viewport coordinates. + * @param {OpenSeadragon.Rect} [options.fitBounds] The bounds in viewport coordinates + * to fit the image into. If specified, x, y, width and height get ignored. + * @param {OpenSeadragon.Placement} [options.fitBoundsPlacement=OpenSeadragon.Placement.CENTER] + * How to anchor the image in the bounds if options.fitBounds is set. + * @param {OpenSeadragon.Rect} [options.clip] - An area, in image pixels, to clip to + * (portions of the image outside of this area will not be visible). Only works on + * browsers that support the HTML5 canvas. + * @param {Number} [options.springStiffness] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.animationTime] - See {@link OpenSeadragon.Options}. + * @param {Number} [options.minZoomImageRatio] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.wrapHorizontal] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.wrapVertical] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.immediateRender] - See {@link OpenSeadragon.Options}. + * @param {Number} [options.blendTime] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.alwaysBlend] - See {@link OpenSeadragon.Options}. + * @param {Number} [options.minPixelRatio] - See {@link OpenSeadragon.Options}. + * @param {Number} [options.smoothTileEdgesMinZoom] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.iOSDevice] - See {@link OpenSeadragon.Options}. + * @param {Number} [options.opacity=1] - Set to draw at proportional opacity. If zero, images will not draw. + * @param {Boolean} [options.preload=false] - Set true to load even when the image is hidden by zero opacity. + * @param {String} [options.compositeOperation] - How the image is composited onto other images; see compositeOperation in {@link OpenSeadragon.Options} for possible values. + * @param {Boolean} [options.debugMode] - See {@link OpenSeadragon.Options}. + * @param {String|CanvasGradient|CanvasPattern|Function} [options.placeholderFillStyle] - See {@link OpenSeadragon.Options}. + * @param {String|Boolean} [options.crossOriginPolicy] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.ajaxWithCredentials] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.loadTilesWithAjax] + * Whether to load tile data using AJAX requests. + * Defaults to the setting in {@link OpenSeadragon.Options}. + * @param {Object} [options.ajaxHeaders={}] + * A set of headers to include when making tile AJAX requests. + */ +$.TiledImage = function( options ) { + var _this = this; + + $.console.assert( options.tileCache, "[TiledImage] options.tileCache is required" ); + $.console.assert( options.drawer, "[TiledImage] options.drawer is required" ); + $.console.assert( options.viewer, "[TiledImage] options.viewer is required" ); + $.console.assert( options.imageLoader, "[TiledImage] options.imageLoader is required" ); + $.console.assert( options.source, "[TiledImage] options.source is required" ); + $.console.assert(!options.clip || options.clip instanceof $.Rect, + "[TiledImage] options.clip must be an OpenSeadragon.Rect if present"); + + $.EventSource.call( this ); + + this._tileCache = options.tileCache; + delete options.tileCache; + + this._drawer = options.drawer; + delete options.drawer; + + this._imageLoader = options.imageLoader; + delete options.imageLoader; + + if (options.clip instanceof $.Rect) { + this._clip = options.clip.clone(); + } + + delete options.clip; + + var x = options.x || 0; + delete options.x; + var y = options.y || 0; + delete options.y; + + // Ratio of zoomable image height to width. + this.normHeight = options.source.dimensions.y / options.source.dimensions.x; + this.contentAspectX = options.source.dimensions.x / options.source.dimensions.y; + + var scale = 1; + if ( options.width ) { + scale = options.width; + delete options.width; + + if ( options.height ) { + $.console.error( "specifying both width and height to a tiledImage is not supported" ); + delete options.height; + } + } else if ( options.height ) { + scale = options.height / this.normHeight; + delete options.height; + } + + var fitBounds = options.fitBounds; + delete options.fitBounds; + var fitBoundsPlacement = options.fitBoundsPlacement || OpenSeadragon.Placement.CENTER; + delete options.fitBoundsPlacement; + + var degrees = options.degrees || 0; + delete options.degrees; + + $.extend( true, this, { + + //internal state properties + viewer: null, + tilesMatrix: {}, // A '3d' dictionary [level][x][y] --> Tile. + coverage: {}, // A '3d' dictionary [level][x][y] --> Boolean; shows what areas have been drawn. + loadingCoverage: {}, // A '3d' dictionary [level][x][y] --> Boolean; shows what areas are loaded or are being loaded/blended. + lastDrawn: [], // An unordered list of Tiles drawn last frame. + lastResetTime: 0, // Last time for which the tiledImage was reset. + _midDraw: false, // Is the tiledImage currently updating the viewport? + _needsDraw: true, // Does the tiledImage need to update the viewport again? + _hasOpaqueTile: false, // Do we have even one fully opaque tile? + _tilesLoading: 0, // The number of pending tile requests. + //configurable settings + springStiffness: $.DEFAULT_SETTINGS.springStiffness, + animationTime: $.DEFAULT_SETTINGS.animationTime, + minZoomImageRatio: $.DEFAULT_SETTINGS.minZoomImageRatio, + wrapHorizontal: $.DEFAULT_SETTINGS.wrapHorizontal, + wrapVertical: $.DEFAULT_SETTINGS.wrapVertical, + immediateRender: $.DEFAULT_SETTINGS.immediateRender, + blendTime: $.DEFAULT_SETTINGS.blendTime, + alwaysBlend: $.DEFAULT_SETTINGS.alwaysBlend, + minPixelRatio: $.DEFAULT_SETTINGS.minPixelRatio, + smoothTileEdgesMinZoom: $.DEFAULT_SETTINGS.smoothTileEdgesMinZoom, + iOSDevice: $.DEFAULT_SETTINGS.iOSDevice, + debugMode: $.DEFAULT_SETTINGS.debugMode, + crossOriginPolicy: $.DEFAULT_SETTINGS.crossOriginPolicy, + ajaxWithCredentials: $.DEFAULT_SETTINGS.ajaxWithCredentials, + placeholderFillStyle: $.DEFAULT_SETTINGS.placeholderFillStyle, + opacity: $.DEFAULT_SETTINGS.opacity, + preload: $.DEFAULT_SETTINGS.preload, + compositeOperation: $.DEFAULT_SETTINGS.compositeOperation + }, options ); + + this._preload = this.preload; + delete this.preload; + + this._fullyLoaded = false; + + this._xSpring = new $.Spring({ + initial: x, + springStiffness: this.springStiffness, + animationTime: this.animationTime + }); + + this._ySpring = new $.Spring({ + initial: y, + springStiffness: this.springStiffness, + animationTime: this.animationTime + }); + + this._scaleSpring = new $.Spring({ + initial: scale, + springStiffness: this.springStiffness, + animationTime: this.animationTime + }); + + this._degreesSpring = new $.Spring({ + initial: degrees, + springStiffness: this.springStiffness, + animationTime: this.animationTime + }); + + this._updateForScale(); + + if (fitBounds) { + this.fitBounds(fitBounds, fitBoundsPlacement, true); + } + + // We need a callback to give image manipulation a chance to happen + this._drawingHandler = function(args) { + /** + * This event is fired just before the tile is drawn giving the application a chance to alter the image. + * + * NOTE: This event is only fired when the drawer is using a <canvas>. + * + * @event tile-drawing + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {OpenSeadragon.Tile} tile - The Tile being drawn. + * @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn. + * @property {OpenSeadragon.Tile} context - The HTML canvas context being drawn into. + * @property {OpenSeadragon.Tile} rendered - The HTML canvas context containing the tile imagery. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.viewer.raiseEvent('tile-drawing', $.extend({ + tiledImage: _this + }, args)); + }; +}; + +$.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.TiledImage.prototype */{ + /** + * @returns {Boolean} Whether the TiledImage needs to be drawn. + */ + needsDraw: function() { + return this._needsDraw; + }, + + /** + * @returns {Boolean} Whether all tiles necessary for this TiledImage to draw at the current view have been loaded. + */ + getFullyLoaded: function() { + return this._fullyLoaded; + }, + + // private + _setFullyLoaded: function(flag) { + if (flag === this._fullyLoaded) { + return; + } + + this._fullyLoaded = flag; + + /** + * Fired when the TiledImage's "fully loaded" flag (whether all tiles necessary for this TiledImage + * to draw at the current view have been loaded) changes. + * + * @event fully-loaded-change + * @memberof OpenSeadragon.TiledImage + * @type {object} + * @property {Boolean} fullyLoaded - The new "fully loaded" value. + * @property {OpenSeadragon.TiledImage} eventSource - A reference to the TiledImage which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('fully-loaded-change', { + fullyLoaded: this._fullyLoaded + }); + }, + + /** + * Clears all tiles and triggers an update on the next call to + * {@link OpenSeadragon.TiledImage#update}. + */ + reset: function() { + this._tileCache.clearTilesFor(this); + this.lastResetTime = $.now(); + this._needsDraw = true; + }, + + /** + * Updates the TiledImage's bounds, animating if needed. + * @returns {Boolean} Whether the TiledImage animated. + */ + update: function() { + var xUpdated = this._xSpring.update(); + var yUpdated = this._ySpring.update(); + var scaleUpdated = this._scaleSpring.update(); + var degreesUpdated = this._degreesSpring.update(); + + if (xUpdated || yUpdated || scaleUpdated || degreesUpdated) { + this._updateForScale(); + this._needsDraw = true; + return true; + } + + return false; + }, + + /** + * Draws the TiledImage to its Drawer. + */ + draw: function() { + if (this.opacity !== 0 || this._preload) { + this._midDraw = true; + this._updateViewport(); + this._midDraw = false; + } + }, + + /** + * Destroy the TiledImage (unload current loaded tiles). + */ + destroy: function() { + this.reset(); + }, + + /** + * Get this TiledImage's bounds in viewport coordinates. + * @param {Boolean} [current=false] - Pass true for the current location; + * false for target location. + * @returns {OpenSeadragon.Rect} This TiledImage's bounds in viewport coordinates. + */ + getBounds: function(current) { + return this.getBoundsNoRotate(current) + .rotate(this.getRotation(current), this._getRotationPoint(current)); + }, + + /** + * Get this TiledImage's bounds in viewport coordinates without taking + * rotation into account. + * @param {Boolean} [current=false] - Pass true for the current location; + * false for target location. + * @returns {OpenSeadragon.Rect} This TiledImage's bounds in viewport coordinates. + */ + getBoundsNoRotate: function(current) { + return current ? + new $.Rect( + this._xSpring.current.value, + this._ySpring.current.value, + this._worldWidthCurrent, + this._worldHeightCurrent) : + new $.Rect( + this._xSpring.target.value, + this._ySpring.target.value, + this._worldWidthTarget, + this._worldHeightTarget); + }, + + // deprecated + getWorldBounds: function() { + $.console.error('[TiledImage.getWorldBounds] is deprecated; use TiledImage.getBounds instead'); + return this.getBounds(); + }, + + /** + * Get the bounds of the displayed part of the tiled image. + * @param {Boolean} [current=false] Pass true for the current location, + * false for the target location. + * @returns {$.Rect} The clipped bounds in viewport coordinates. + */ + getClippedBounds: function(current) { + var bounds = this.getBoundsNoRotate(current); + if (this._clip) { + var worldWidth = current ? + this._worldWidthCurrent : this._worldWidthTarget; + var ratio = worldWidth / this.source.dimensions.x; + var clip = this._clip.times(ratio); + bounds = new $.Rect( + bounds.x + clip.x, + bounds.y + clip.y, + clip.width, + clip.height); + } + return bounds.rotate(this.getRotation(current), this._getRotationPoint(current)); + }, + + /** + * @returns {OpenSeadragon.Point} This TiledImage's content size, in original pixels. + */ + getContentSize: function() { + return new $.Point(this.source.dimensions.x, this.source.dimensions.y); + }, + + // private + _viewportToImageDelta: function( viewerX, viewerY, current ) { + var scale = (current ? this._scaleSpring.current.value : this._scaleSpring.target.value); + return new $.Point(viewerX * (this.source.dimensions.x / scale), + viewerY * ((this.source.dimensions.y * this.contentAspectX) / scale)); + }, + + /** + * Translates from OpenSeadragon viewer coordinate system to image coordinate system. + * This method can be called either by passing X,Y coordinates or an {@link OpenSeadragon.Point}. + * @param {Number|OpenSeadragon.Point} viewerX - The X coordinate or point in viewport coordinate system. + * @param {Number} [viewerY] - The Y coordinate in viewport coordinate system. + * @param {Boolean} [current=false] - Pass true to use the current location; false for target location. + * @return {OpenSeadragon.Point} A point representing the coordinates in the image. + */ + viewportToImageCoordinates: function(viewerX, viewerY, current) { + var point; + if (viewerX instanceof $.Point) { + //they passed a point instead of individual components + current = viewerY; + point = viewerX; + } else { + point = new $.Point(viewerX, viewerY); + } + + point = point.rotate(-this.getRotation(current), this._getRotationPoint(current)); + return current ? + this._viewportToImageDelta( + point.x - this._xSpring.current.value, + point.y - this._ySpring.current.value) : + this._viewportToImageDelta( + point.x - this._xSpring.target.value, + point.y - this._ySpring.target.value); + }, + + // private + _imageToViewportDelta: function( imageX, imageY, current ) { + var scale = (current ? this._scaleSpring.current.value : this._scaleSpring.target.value); + return new $.Point((imageX / this.source.dimensions.x) * scale, + (imageY / this.source.dimensions.y / this.contentAspectX) * scale); + }, + + /** + * Translates from image coordinate system to OpenSeadragon viewer coordinate system + * This method can be called either by passing X,Y coordinates or an {@link OpenSeadragon.Point}. + * @param {Number|OpenSeadragon.Point} imageX - The X coordinate or point in image coordinate system. + * @param {Number} [imageY] - The Y coordinate in image coordinate system. + * @param {Boolean} [current=false] - Pass true to use the current location; false for target location. + * @return {OpenSeadragon.Point} A point representing the coordinates in the viewport. + */ + imageToViewportCoordinates: function(imageX, imageY, current) { + if (imageX instanceof $.Point) { + //they passed a point instead of individual components + current = imageY; + imageY = imageX.y; + imageX = imageX.x; + } + + var point = this._imageToViewportDelta(imageX, imageY); + if (current) { + point.x += this._xSpring.current.value; + point.y += this._ySpring.current.value; + } else { + point.x += this._xSpring.target.value; + point.y += this._ySpring.target.value; + } + + return point.rotate(this.getRotation(current), this._getRotationPoint(current)); + }, + + /** + * Translates from a rectangle which describes a portion of the image in + * pixel coordinates to OpenSeadragon viewport rectangle coordinates. + * This method can be called either by passing X,Y,width,height or an {@link OpenSeadragon.Rect}. + * @param {Number|OpenSeadragon.Rect} imageX - The left coordinate or rectangle in image coordinate system. + * @param {Number} [imageY] - The top coordinate in image coordinate system. + * @param {Number} [pixelWidth] - The width in pixel of the rectangle. + * @param {Number} [pixelHeight] - The height in pixel of the rectangle. + * @param {Boolean} [current=false] - Pass true to use the current location; false for target location. + * @return {OpenSeadragon.Rect} A rect representing the coordinates in the viewport. + */ + imageToViewportRectangle: function(imageX, imageY, pixelWidth, pixelHeight, current) { + var rect = imageX; + if (rect instanceof $.Rect) { + //they passed a rect instead of individual components + current = imageY; + } else { + rect = new $.Rect(imageX, imageY, pixelWidth, pixelHeight); + } + + var coordA = this.imageToViewportCoordinates(rect.getTopLeft(), current); + var coordB = this._imageToViewportDelta(rect.width, rect.height, current); + + return new $.Rect( + coordA.x, + coordA.y, + coordB.x, + coordB.y, + rect.degrees + this.getRotation(current) + ); + }, + + /** + * Translates from a rectangle which describes a portion of + * the viewport in point coordinates to image rectangle coordinates. + * This method can be called either by passing X,Y,width,height or an {@link OpenSeadragon.Rect}. + * @param {Number|OpenSeadragon.Rect} viewerX - The left coordinate or rectangle in viewport coordinate system. + * @param {Number} [viewerY] - The top coordinate in viewport coordinate system. + * @param {Number} [pointWidth] - The width in viewport coordinate system. + * @param {Number} [pointHeight] - The height in viewport coordinate system. + * @param {Boolean} [current=false] - Pass true to use the current location; false for target location. + * @return {OpenSeadragon.Rect} A rect representing the coordinates in the image. + */ + viewportToImageRectangle: function( viewerX, viewerY, pointWidth, pointHeight, current ) { + var rect = viewerX; + if (viewerX instanceof $.Rect) { + //they passed a rect instead of individual components + current = viewerY; + } else { + rect = new $.Rect(viewerX, viewerY, pointWidth, pointHeight); + } + + var coordA = this.viewportToImageCoordinates(rect.getTopLeft(), current); + var coordB = this._viewportToImageDelta(rect.width, rect.height, current); + + return new $.Rect( + coordA.x, + coordA.y, + coordB.x, + coordB.y, + rect.degrees - this.getRotation(current) + ); + }, + + /** + * Convert pixel coordinates relative to the viewer element to image + * coordinates. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + viewerElementToImageCoordinates: function( pixel ) { + var point = this.viewport.pointFromPixel( pixel, true ); + return this.viewportToImageCoordinates( point ); + }, + + /** + * Convert pixel coordinates relative to the image to + * viewer element coordinates. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + imageToViewerElementCoordinates: function( pixel ) { + var point = this.imageToViewportCoordinates( pixel ); + return this.viewport.pixelFromPoint( point, true ); + }, + + /** + * Convert pixel coordinates relative to the window to image coordinates. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + windowToImageCoordinates: function( pixel ) { + var viewerCoordinates = pixel.minus( + OpenSeadragon.getElementPosition( this.viewer.element )); + return this.viewerElementToImageCoordinates( viewerCoordinates ); + }, + + /** + * Convert image coordinates to pixel coordinates relative to the window. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + imageToWindowCoordinates: function( pixel ) { + var viewerCoordinates = this.imageToViewerElementCoordinates( pixel ); + return viewerCoordinates.plus( + OpenSeadragon.getElementPosition( this.viewer.element )); + }, + + // private + // Convert rectangle in viewport coordinates to this tiled image point + // coordinates (x in [0, 1] and y in [0, aspectRatio]) + _viewportToTiledImageRectangle: function(rect) { + var scale = this._scaleSpring.current.value; + rect = rect.rotate(-this.getRotation(true), this._getRotationPoint(true)); + return new $.Rect( + (rect.x - this._xSpring.current.value) / scale, + (rect.y - this._ySpring.current.value) / scale, + rect.width / scale, + rect.height / scale, + rect.degrees); + }, + + /** + * Convert a viewport zoom to an image zoom. + * Image zoom: ratio of the original image size to displayed image size. + * 1 means original image size, 0.5 half size... + * Viewport zoom: ratio of the displayed image's width to viewport's width. + * 1 means identical width, 2 means image's width is twice the viewport's width... + * @function + * @param {Number} viewportZoom The viewport zoom + * @returns {Number} imageZoom The image zoom + */ + viewportToImageZoom: function( viewportZoom ) { + var ratio = this._scaleSpring.current.value * + this.viewport._containerInnerSize.x / this.source.dimensions.x; + return ratio * viewportZoom; + }, + + /** + * Convert an image zoom to a viewport zoom. + * Image zoom: ratio of the original image size to displayed image size. + * 1 means original image size, 0.5 half size... + * Viewport zoom: ratio of the displayed image's width to viewport's width. + * 1 means identical width, 2 means image's width is twice the viewport's width... + * Note: not accurate with multi-image. + * @function + * @param {Number} imageZoom The image zoom + * @returns {Number} viewportZoom The viewport zoom + */ + imageToViewportZoom: function( imageZoom ) { + var ratio = this._scaleSpring.current.value * + this.viewport._containerInnerSize.x / this.source.dimensions.x; + return imageZoom / ratio; + }, + + /** + * Sets the TiledImage's position in the world. + * @param {OpenSeadragon.Point} position - The new position, in viewport coordinates. + * @param {Boolean} [immediately=false] - Whether to animate to the new position or snap immediately. + * @fires OpenSeadragon.TiledImage.event:bounds-change + */ + setPosition: function(position, immediately) { + var sameTarget = (this._xSpring.target.value === position.x && + this._ySpring.target.value === position.y); + + if (immediately) { + if (sameTarget && this._xSpring.current.value === position.x && + this._ySpring.current.value === position.y) { + return; + } + + this._xSpring.resetTo(position.x); + this._ySpring.resetTo(position.y); + this._needsDraw = true; + } else { + if (sameTarget) { + return; + } + + this._xSpring.springTo(position.x); + this._ySpring.springTo(position.y); + this._needsDraw = true; + } + + if (!sameTarget) { + this._raiseBoundsChange(); + } + }, + + /** + * Sets the TiledImage's width in the world, adjusting the height to match based on aspect ratio. + * @param {Number} width - The new width, in viewport coordinates. + * @param {Boolean} [immediately=false] - Whether to animate to the new size or snap immediately. + * @fires OpenSeadragon.TiledImage.event:bounds-change + */ + setWidth: function(width, immediately) { + this._setScale(width, immediately); + }, + + /** + * Sets the TiledImage's height in the world, adjusting the width to match based on aspect ratio. + * @param {Number} height - The new height, in viewport coordinates. + * @param {Boolean} [immediately=false] - Whether to animate to the new size or snap immediately. + * @fires OpenSeadragon.TiledImage.event:bounds-change + */ + setHeight: function(height, immediately) { + this._setScale(height / this.normHeight, immediately); + }, + + /** + * Positions and scales the TiledImage to fit in the specified bounds. + * Note: this method fires OpenSeadragon.TiledImage.event:bounds-change + * twice + * @param {OpenSeadragon.Rect} bounds The bounds to fit the image into. + * @param {OpenSeadragon.Placement} [anchor=OpenSeadragon.Placement.CENTER] + * How to anchor the image in the bounds. + * @param {Boolean} [immediately=false] Whether to animate to the new size + * or snap immediately. + * @fires OpenSeadragon.TiledImage.event:bounds-change + */ + fitBounds: function(bounds, anchor, immediately) { + anchor = anchor || $.Placement.CENTER; + var anchorProperties = $.Placement.properties[anchor]; + var aspectRatio = this.contentAspectX; + var xOffset = 0; + var yOffset = 0; + var displayedWidthRatio = 1; + var displayedHeightRatio = 1; + if (this._clip) { + aspectRatio = this._clip.getAspectRatio(); + displayedWidthRatio = this._clip.width / this.source.dimensions.x; + displayedHeightRatio = this._clip.height / this.source.dimensions.y; + if (bounds.getAspectRatio() > aspectRatio) { + xOffset = this._clip.x / this._clip.height * bounds.height; + yOffset = this._clip.y / this._clip.height * bounds.height; + } else { + xOffset = this._clip.x / this._clip.width * bounds.width; + yOffset = this._clip.y / this._clip.width * bounds.width; + } + } + + if (bounds.getAspectRatio() > aspectRatio) { + // We will have margins on the X axis + var height = bounds.height / displayedHeightRatio; + var marginLeft = 0; + if (anchorProperties.isHorizontallyCentered) { + marginLeft = (bounds.width - bounds.height * aspectRatio) / 2; + } else if (anchorProperties.isRight) { + marginLeft = bounds.width - bounds.height * aspectRatio; + } + this.setPosition( + new $.Point(bounds.x - xOffset + marginLeft, bounds.y - yOffset), + immediately); + this.setHeight(height, immediately); + } else { + // We will have margins on the Y axis + var width = bounds.width / displayedWidthRatio; + var marginTop = 0; + if (anchorProperties.isVerticallyCentered) { + marginTop = (bounds.height - bounds.width / aspectRatio) / 2; + } else if (anchorProperties.isBottom) { + marginTop = bounds.height - bounds.width / aspectRatio; + } + this.setPosition( + new $.Point(bounds.x - xOffset, bounds.y - yOffset + marginTop), + immediately); + this.setWidth(width, immediately); + } + }, + + /** + * @returns {OpenSeadragon.Rect|null} The TiledImage's current clip rectangle, + * in image pixels, or null if none. + */ + getClip: function() { + if (this._clip) { + return this._clip.clone(); + } + + return null; + }, + + /** + * @param {OpenSeadragon.Rect|null} newClip - An area, in image pixels, to clip to + * (portions of the image outside of this area will not be visible). Only works on + * browsers that support the HTML5 canvas. + * @fires OpenSeadragon.TiledImage.event:clip-change + */ + setClip: function(newClip) { + $.console.assert(!newClip || newClip instanceof $.Rect, + "[TiledImage.setClip] newClip must be an OpenSeadragon.Rect or null"); + + if (newClip instanceof $.Rect) { + this._clip = newClip.clone(); + } else { + this._clip = null; + } + + this._needsDraw = true; + /** + * Raised when the TiledImage's clip is changed. + * @event clip-change + * @memberOf OpenSeadragon.TiledImage + * @type {object} + * @property {OpenSeadragon.TiledImage} eventSource - A reference to the + * TiledImage which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('clip-change'); + }, + + /** + * @returns {Number} The TiledImage's current opacity. + */ + getOpacity: function() { + return this.opacity; + }, + + /** + * @param {Number} opacity Opacity the tiled image should be drawn at. + * @fires OpenSeadragon.TiledImage.event:opacity-change + */ + setOpacity: function(opacity) { + if (opacity === this.opacity) { + return; + } + + this.opacity = opacity; + this._needsDraw = true; + /** + * Raised when the TiledImage's opacity is changed. + * @event opacity-change + * @memberOf OpenSeadragon.TiledImage + * @type {object} + * @property {Number} opacity - The new opacity value. + * @property {OpenSeadragon.TiledImage} eventSource - A reference to the + * TiledImage which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('opacity-change', { + opacity: this.opacity + }); + }, + + /** + * @returns {Boolean} whether the tiledImage can load its tiles even when it has zero opacity. + */ + getPreload: function() { + return this._preload; + }, + + /** + * Set true to load even when hidden. Set false to block loading when hidden. + */ + setPreload: function(preload) { + this._preload = !!preload; + this._needsDraw = true; + }, + + /** + * Get the rotation of this tiled image in degrees. + * @param {Boolean} [current=false] True for current rotation, false for target. + * @returns {Number} the rotation of this tiled image in degrees. + */ + getRotation: function(current) { + return current ? + this._degreesSpring.current.value : + this._degreesSpring.target.value; + }, + + /** + * Set the current rotation of this tiled image in degrees. + * @param {Number} degrees the rotation in degrees. + * @param {Boolean} [immediately=false] Whether to animate to the new angle + * or rotate immediately. + * @fires OpenSeadragon.TiledImage.event:bounds-change + */ + setRotation: function(degrees, immediately) { + if (this._degreesSpring.target.value === degrees && + this._degreesSpring.isAtTargetValue()) { + return; + } + if (immediately) { + this._degreesSpring.resetTo(degrees); + } else { + this._degreesSpring.springTo(degrees); + } + this._needsDraw = true; + this._raiseBoundsChange(); + }, + + /** + * Get the point around which this tiled image is rotated + * @private + * @param {Boolean} current True for current rotation point, false for target. + * @returns {OpenSeadragon.Point} + */ + _getRotationPoint: function(current) { + return this.getBoundsNoRotate(current).getCenter(); + }, + + /** + * @returns {String} The TiledImage's current compositeOperation. + */ + getCompositeOperation: function() { + return this.compositeOperation; + }, + + /** + * @param {String} compositeOperation the tiled image should be drawn with this globalCompositeOperation. + * @fires OpenSeadragon.TiledImage.event:composite-operation-change + */ + setCompositeOperation: function(compositeOperation) { + if (compositeOperation === this.compositeOperation) { + return; + } + + this.compositeOperation = compositeOperation; + this._needsDraw = true; + /** + * Raised when the TiledImage's opacity is changed. + * @event composite-operation-change + * @memberOf OpenSeadragon.TiledImage + * @type {object} + * @property {String} compositeOperation - The new compositeOperation value. + * @property {OpenSeadragon.TiledImage} eventSource - A reference to the + * TiledImage which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('composite-operation-change', { + compositeOperation: this.compositeOperation + }); + }, + + // private + _setScale: function(scale, immediately) { + var sameTarget = (this._scaleSpring.target.value === scale); + if (immediately) { + if (sameTarget && this._scaleSpring.current.value === scale) { + return; + } + + this._scaleSpring.resetTo(scale); + this._updateForScale(); + this._needsDraw = true; + } else { + if (sameTarget) { + return; + } + + this._scaleSpring.springTo(scale); + this._updateForScale(); + this._needsDraw = true; + } + + if (!sameTarget) { + this._raiseBoundsChange(); + } + }, + + // private + _updateForScale: function() { + this._worldWidthTarget = this._scaleSpring.target.value; + this._worldHeightTarget = this.normHeight * this._scaleSpring.target.value; + this._worldWidthCurrent = this._scaleSpring.current.value; + this._worldHeightCurrent = this.normHeight * this._scaleSpring.current.value; + }, + + // private + _raiseBoundsChange: function() { + /** + * Raised when the TiledImage's bounds are changed. + * Note that this event is triggered only when the animation target is changed; + * not for every frame of animation. + * @event bounds-change + * @memberOf OpenSeadragon.TiledImage + * @type {object} + * @property {OpenSeadragon.TiledImage} eventSource - A reference to the + * TiledImage which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('bounds-change'); + }, + + // private + _isBottomItem: function() { + return this.viewer.world.getItemAt(0) === this; + }, + + // private + _getLevelsInterval: function() { + var lowestLevel = Math.max( + this.source.minLevel, + Math.floor(Math.log(this.minZoomImageRatio) / Math.log(2)) + ); + var currentZeroRatio = this.viewport.deltaPixelsFromPointsNoRotate( + this.source.getPixelRatio(0), true).x * + this._scaleSpring.current.value; + var highestLevel = Math.min( + Math.abs(this.source.maxLevel), + Math.abs(Math.floor( + Math.log(currentZeroRatio / this.minPixelRatio) / Math.log(2) + )) + ); + + // Calculations for the interval of levels to draw + // can return invalid intervals; fix that here if necessary + lowestLevel = Math.min(lowestLevel, highestLevel); + return { + lowestLevel: lowestLevel, + highestLevel: highestLevel + }; + }, + + /** + * @private + * @inner + * Pretty much every other line in this needs to be documented so it's clear + * how each piece of this routine contributes to the drawing process. That's + * why there are so many TODO's inside this function. + */ + _updateViewport: function() { + this._needsDraw = false; + this._tilesLoading = 0; + this.loadingCoverage = {}; + + // Reset tile's internal drawn state + while (this.lastDrawn.length > 0) { + var tile = this.lastDrawn.pop(); + tile.beingDrawn = false; + } + + var viewport = this.viewport; + var drawArea = this._viewportToTiledImageRectangle( + viewport.getBoundsWithMargins(true)); + + if (!this.wrapHorizontal && !this.wrapVertical) { + var tiledImageBounds = this._viewportToTiledImageRectangle( + this.getClippedBounds(true)); + drawArea = drawArea.intersection(tiledImageBounds); + if (drawArea === null) { + return; + } + } + + var levelsInterval = this._getLevelsInterval(); + var lowestLevel = levelsInterval.lowestLevel; + var highestLevel = levelsInterval.highestLevel; + var bestTile = null; + var haveDrawn = false; + var currentTime = $.now(); + + // Update any level that will be drawn + for (var level = highestLevel; level >= lowestLevel; level--) { + var drawLevel = false; + + //Avoid calculations for draw if we have already drawn this + var currentRenderPixelRatio = viewport.deltaPixelsFromPointsNoRotate( + this.source.getPixelRatio(level), + true + ).x * this._scaleSpring.current.value; + + if (level === lowestLevel || + (!haveDrawn && currentRenderPixelRatio >= this.minPixelRatio)) { + drawLevel = true; + haveDrawn = true; + } else if (!haveDrawn) { + continue; + } + + //Perform calculations for draw if we haven't drawn this + var targetRenderPixelRatio = viewport.deltaPixelsFromPointsNoRotate( + this.source.getPixelRatio(level), + false + ).x * this._scaleSpring.current.value; + + var targetZeroRatio = viewport.deltaPixelsFromPointsNoRotate( + this.source.getPixelRatio( + Math.max( + this.source.getClosestLevel(), + 0 + ) + ), + false + ).x * this._scaleSpring.current.value; + + var optimalRatio = this.immediateRender ? 1 : targetZeroRatio; + var levelOpacity = Math.min(1, (currentRenderPixelRatio - 0.5) / 0.5); + var levelVisibility = optimalRatio / Math.abs( + optimalRatio - targetRenderPixelRatio + ); + + // Update the level and keep track of 'best' tile to load + bestTile = updateLevel( + this, + haveDrawn, + drawLevel, + level, + levelOpacity, + levelVisibility, + drawArea, + currentTime, + bestTile + ); + + // Stop the loop if lower-res tiles would all be covered by + // already drawn tiles + if (providesCoverage(this.coverage, level)) { + break; + } + } + + // Perform the actual drawing + drawTiles(this, this.lastDrawn); + + // Load the new 'best' tile + if (bestTile && !bestTile.context2D) { + loadTile(this, bestTile, currentTime); + this._needsDraw = true; + this._setFullyLoaded(false); + } else { + this._setFullyLoaded(this._tilesLoading === 0); + } + }, + + // private + _getCornerTiles: function(level, topLeftBound, bottomRightBound) { + var leftX; + var rightX; + if (this.wrapHorizontal) { + leftX = $.positiveModulo(topLeftBound.x, 1); + rightX = $.positiveModulo(bottomRightBound.x, 1); + } else { + leftX = Math.max(0, topLeftBound.x); + rightX = Math.min(1, bottomRightBound.x); + } + var topY; + var bottomY; + var aspectRatio = 1 / this.source.aspectRatio; + if (this.wrapVertical) { + topY = $.positiveModulo(topLeftBound.y, aspectRatio); + bottomY = $.positiveModulo(bottomRightBound.y, aspectRatio); + } else { + topY = Math.max(0, topLeftBound.y); + bottomY = Math.min(aspectRatio, bottomRightBound.y); + } + + var topLeftTile = this.source.getTileAtPoint(level, new $.Point(leftX, topY)); + var bottomRightTile = this.source.getTileAtPoint(level, new $.Point(rightX, bottomY)); + var numTiles = this.source.getNumTiles(level); + + if (this.wrapHorizontal) { + topLeftTile.x += numTiles.x * Math.floor(topLeftBound.x); + bottomRightTile.x += numTiles.x * Math.floor(bottomRightBound.x); + } + if (this.wrapVertical) { + topLeftTile.y += numTiles.y * Math.floor(topLeftBound.y / aspectRatio); + bottomRightTile.y += numTiles.y * Math.floor(bottomRightBound.y / aspectRatio); + } + + return { + topLeft: topLeftTile, + bottomRight: bottomRightTile, + }; + } +}); + +/** + * @private + * @inner + * Updates all tiles at a given resolution level. + * @param {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn. + * @param {Boolean} haveDrawn + * @param {Boolean} drawLevel + * @param {Number} level + * @param {Number} levelOpacity + * @param {Number} levelVisibility + * @param {OpenSeadragon.Point} viewportTL - The index of the most top-left visible tile. + * @param {OpenSeadragon.Point} viewportBR - The index of the most bottom-right visible tile. + * @param {Number} currentTime + * @param {OpenSeadragon.Tile} best - The current "best" tile to draw. + */ +function updateLevel(tiledImage, haveDrawn, drawLevel, level, levelOpacity, + levelVisibility, drawArea, currentTime, best) { + + var topLeftBound = drawArea.getBoundingBox().getTopLeft(); + var bottomRightBound = drawArea.getBoundingBox().getBottomRight(); + + if (tiledImage.viewer) { + /** + * - Needs documentation - + * + * @event update-level + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn. + * @property {Object} havedrawn + * @property {Object} level + * @property {Object} opacity + * @property {Object} visibility + * @property {OpenSeadragon.Rect} drawArea + * @property {Object} topleft deprecated, use drawArea instead + * @property {Object} bottomright deprecated, use drawArea instead + * @property {Object} currenttime + * @property {Object} best + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + tiledImage.viewer.raiseEvent('update-level', { + tiledImage: tiledImage, + havedrawn: haveDrawn, + level: level, + opacity: levelOpacity, + visibility: levelVisibility, + drawArea: drawArea, + topleft: topLeftBound, + bottomright: bottomRightBound, + currenttime: currentTime, + best: best + }); + } + + resetCoverage(tiledImage.coverage, level); + resetCoverage(tiledImage.loadingCoverage, level); + + //OK, a new drawing so do your calculations + var cornerTiles = tiledImage._getCornerTiles(level, topLeftBound, bottomRightBound); + var topLeftTile = cornerTiles.topLeft; + var bottomRightTile = cornerTiles.bottomRight; + var numberOfTiles = tiledImage.source.getNumTiles(level); + + var viewportCenter = tiledImage.viewport.pixelFromPoint( + tiledImage.viewport.getCenter()); + for (var x = topLeftTile.x; x <= bottomRightTile.x; x++) { + for (var y = topLeftTile.y; y <= bottomRightTile.y; y++) { + + // Optimisation disabled with wrapping because getTileBounds does not + // work correctly with x and y outside of the number of tiles + if (!tiledImage.wrapHorizontal && !tiledImage.wrapVertical) { + var tileBounds = tiledImage.source.getTileBounds(level, x, y); + if (drawArea.intersection(tileBounds) === null) { + // This tile is outside of the viewport, no need to draw it + continue; + } + } + + best = updateTile( + tiledImage, + drawLevel, + haveDrawn, + x, y, + level, + levelOpacity, + levelVisibility, + viewportCenter, + numberOfTiles, + currentTime, + best + ); + + } + } + + return best; +} + +/** + * @private + * @inner + * Update a single tile at a particular resolution level. + * @param {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn. + * @param {Boolean} haveDrawn + * @param {Boolean} drawLevel + * @param {Number} x + * @param {Number} y + * @param {Number} level + * @param {Number} levelOpacity + * @param {Number} levelVisibility + * @param {OpenSeadragon.Point} viewportCenter + * @param {Number} numberOfTiles + * @param {Number} currentTime + * @param {OpenSeadragon.Tile} best - The current "best" tile to draw. + */ +function updateTile( tiledImage, haveDrawn, drawLevel, x, y, level, levelOpacity, levelVisibility, viewportCenter, numberOfTiles, currentTime, best){ + + var tile = getTile( + x, y, + level, + tiledImage, + tiledImage.source, + tiledImage.tilesMatrix, + currentTime, + numberOfTiles, + tiledImage._worldWidthCurrent, + tiledImage._worldHeightCurrent + ), + drawTile = drawLevel; + + if( tiledImage.viewer ){ + /** + * - Needs documentation - + * + * @event update-tile + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn. + * @property {OpenSeadragon.Tile} tile + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + tiledImage.viewer.raiseEvent( 'update-tile', { + tiledImage: tiledImage, + tile: tile + }); + } + + setCoverage( tiledImage.coverage, level, x, y, false ); + + var loadingCoverage = tile.loaded || tile.loading || isCovered(tiledImage.loadingCoverage, level, x, y); + setCoverage(tiledImage.loadingCoverage, level, x, y, loadingCoverage); + + if ( !tile.exists ) { + return best; + } + + if ( haveDrawn && !drawTile ) { + if ( isCovered( tiledImage.coverage, level, x, y ) ) { + setCoverage( tiledImage.coverage, level, x, y, true ); + } else { + drawTile = true; + } + } + + if ( !drawTile ) { + return best; + } + + positionTile( + tile, + tiledImage.source.tileOverlap, + tiledImage.viewport, + viewportCenter, + levelVisibility, + tiledImage + ); + + if (!tile.loaded) { + if (tile.context2D) { + setTileLoaded(tiledImage, tile); + } else { + var imageRecord = tiledImage._tileCache.getImageRecord(tile.cacheKey); + if (imageRecord) { + var image = imageRecord.getImage(); + setTileLoaded(tiledImage, tile, image); + } + } + } + + if ( tile.loaded ) { + var needsDraw = blendTile( + tiledImage, + tile, + x, y, + level, + levelOpacity, + currentTime + ); + + if ( needsDraw ) { + tiledImage._needsDraw = true; + } + } else if ( tile.loading ) { + // the tile is already in the download queue + tiledImage._tilesLoading++; + } else if (!loadingCoverage) { + best = compareTiles( best, tile ); + } + + return best; +} + +/** + * @private + * @inner + * Obtains a tile at the given location. + * @param {Number} x + * @param {Number} y + * @param {Number} level + * @param {OpenSeadragon.TiledImage} tiledImage + * @param {OpenSeadragon.TileSource} tileSource + * @param {Object} tilesMatrix - A '3d' dictionary [level][x][y] --> Tile. + * @param {Number} time + * @param {Number} numTiles + * @param {Number} worldWidth + * @param {Number} worldHeight + * @returns {OpenSeadragon.Tile} + */ +function getTile( + x, y, + level, + tiledImage, + tileSource, + tilesMatrix, + time, + numTiles, + worldWidth, + worldHeight +) { + var xMod, + yMod, + bounds, + exists, + url, + ajaxHeaders, + context2D, + tile; + + if ( !tilesMatrix[ level ] ) { + tilesMatrix[ level ] = {}; + } + if ( !tilesMatrix[ level ][ x ] ) { + tilesMatrix[ level ][ x ] = {}; + } + + if ( !tilesMatrix[ level ][ x ][ y ] ) { + xMod = ( numTiles.x + ( x % numTiles.x ) ) % numTiles.x; + yMod = ( numTiles.y + ( y % numTiles.y ) ) % numTiles.y; + bounds = tileSource.getTileBounds( level, xMod, yMod ); + exists = tileSource.tileExists( level, xMod, yMod ); + url = tileSource.getTileUrl( level, xMod, yMod ); + + // Headers are only applicable if loadTilesWithAjax is set + if (tiledImage.loadTilesWithAjax) { + ajaxHeaders = tileSource.getTileAjaxHeaders( level, xMod, yMod ); + // Combine tile AJAX headers with tiled image AJAX headers (if applicable) + if ($.isPlainObject(tiledImage.ajaxHeaders)) { + ajaxHeaders = $.extend({}, tiledImage.ajaxHeaders, ajaxHeaders); + } + } else { + ajaxHeaders = null; + } + + context2D = tileSource.getContext2D ? + tileSource.getContext2D(level, xMod, yMod) : undefined; + + bounds.x += ( x - xMod ) / numTiles.x; + bounds.y += (worldHeight / worldWidth) * (( y - yMod ) / numTiles.y); + + tile = new $.Tile( + level, + x, + y, + bounds, + exists, + url, + context2D, + tiledImage.loadTilesWithAjax, + ajaxHeaders + ); + + if (xMod === numTiles.x - 1) { + tile.isRightMost = true; + } + + if (yMod === numTiles.y - 1) { + tile.isBottomMost = true; + } + + tilesMatrix[ level ][ x ][ y ] = tile; + } + + tile = tilesMatrix[ level ][ x ][ y ]; + tile.lastTouchTime = time; + + return tile; +} + +/** + * @private + * @inner + * Dispatch a job to the ImageLoader to load the Image for a Tile. + * @param {OpenSeadragon.TiledImage} tiledImage + * @param {OpenSeadragon.Tile} tile + * @param {Number} time + */ +function loadTile( tiledImage, tile, time ) { + tile.loading = true; + tiledImage._imageLoader.addJob({ + src: tile.url, + loadWithAjax: tile.loadWithAjax, + ajaxHeaders: tile.ajaxHeaders, + crossOriginPolicy: tiledImage.crossOriginPolicy, + ajaxWithCredentials: tiledImage.ajaxWithCredentials, + callback: function( image, errorMsg, tileRequest ){ + onTileLoad( tiledImage, tile, time, image, errorMsg, tileRequest ); + }, + abort: function() { + tile.loading = false; + } + }); +} + +/** + * @private + * @inner + * Callback fired when a Tile's Image finished downloading. + * @param {OpenSeadragon.TiledImage} tiledImage + * @param {OpenSeadragon.Tile} tile + * @param {Number} time + * @param {Image} image + * @param {String} errorMsg + * @param {XMLHttpRequest} tileRequest + */ +function onTileLoad( tiledImage, tile, time, image, errorMsg, tileRequest ) { + if ( !image ) { + $.console.log( "Tile %s failed to load: %s - error: %s", tile, tile.url, errorMsg ); + /** + * Triggered when a tile fails to load. + * + * @event tile-load-failed + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Tile} tile - The tile that failed to load. + * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image the tile belongs to. + * @property {number} time - The time in milliseconds when the tile load began. + * @property {string} message - The error message. + * @property {XMLHttpRequest} tileRequest - The XMLHttpRequest used to load the tile if available. + */ + tiledImage.viewer.raiseEvent("tile-load-failed", { + tile: tile, + tiledImage: tiledImage, + time: time, + message: errorMsg, + tileRequest: tileRequest + }); + tile.loading = false; + tile.exists = false; + return; + } + + if ( time < tiledImage.lastResetTime ) { + $.console.log( "Ignoring tile %s loaded before reset: %s", tile, tile.url ); + tile.loading = false; + return; + } + + var finish = function() { + var cutoff = tiledImage.source.getClosestLevel(); + setTileLoaded(tiledImage, tile, image, cutoff, tileRequest); + }; + + // Check if we're mid-update; this can happen on IE8 because image load events for + // cached images happen immediately there + if ( !tiledImage._midDraw ) { + finish(); + } else { + // Wait until after the update, in case caching unloads any tiles + window.setTimeout( finish, 1); + } +} + +/** + * @private + * @inner + * @param {OpenSeadragon.TiledImage} tiledImage + * @param {OpenSeadragon.Tile} tile + * @param {Image} image + * @param {Number} cutoff + */ +function setTileLoaded(tiledImage, tile, image, cutoff, tileRequest) { + var increment = 0; + + function getCompletionCallback() { + increment++; + return completionCallback; + } + + function completionCallback() { + increment--; + if (increment === 0) { + tile.loading = false; + tile.loaded = true; + if (!tile.context2D) { + tiledImage._tileCache.cacheTile({ + image: image, + tile: tile, + cutoff: cutoff, + tiledImage: tiledImage + }); + } + tiledImage._needsDraw = true; + } + } + + /** + * Triggered when a tile has just been loaded in memory. That means that the + * image has been downloaded and can be modified before being drawn to the canvas. + * + * @event tile-loaded + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {Image} image - The image of the tile. + * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image of the loaded tile. + * @property {OpenSeadragon.Tile} tile - The tile which has been loaded. + * @property {XMLHttpRequest} tiledImage - The AJAX request that loaded this tile (if applicable). + * @property {function} getCompletionCallback - A function giving a callback to call + * when the asynchronous processing of the image is done. The image will be + * marked as entirely loaded when the callback has been called once for each + * call to getCompletionCallback. + */ + tiledImage.viewer.raiseEvent("tile-loaded", { + tile: tile, + tiledImage: tiledImage, + tileRequest: tileRequest, + image: image, + getCompletionCallback: getCompletionCallback + }); + // In case the completion callback is never called, we at least force it once. + getCompletionCallback()(); +} + +/** + * @private + * @inner + * @param {OpenSeadragon.Tile} tile + * @param {Boolean} overlap + * @param {OpenSeadragon.Viewport} viewport + * @param {OpenSeadragon.Point} viewportCenter + * @param {Number} levelVisibility + * @param {OpenSeadragon.TiledImage} tiledImage + */ +function positionTile( tile, overlap, viewport, viewportCenter, levelVisibility, tiledImage ){ + var boundsTL = tile.bounds.getTopLeft(); + + boundsTL.x *= tiledImage._scaleSpring.current.value; + boundsTL.y *= tiledImage._scaleSpring.current.value; + boundsTL.x += tiledImage._xSpring.current.value; + boundsTL.y += tiledImage._ySpring.current.value; + + var boundsSize = tile.bounds.getSize(); + + boundsSize.x *= tiledImage._scaleSpring.current.value; + boundsSize.y *= tiledImage._scaleSpring.current.value; + + var positionC = viewport.pixelFromPointNoRotate(boundsTL, true), + positionT = viewport.pixelFromPointNoRotate(boundsTL, false), + sizeC = viewport.deltaPixelsFromPointsNoRotate(boundsSize, true), + sizeT = viewport.deltaPixelsFromPointsNoRotate(boundsSize, false), + tileCenter = positionT.plus( sizeT.divide( 2 ) ), + tileSquaredDistance = viewportCenter.squaredDistanceTo( tileCenter ); + + if ( !overlap ) { + sizeC = sizeC.plus( new $.Point( 1, 1 ) ); + } + + if (tile.isRightMost && tiledImage.wrapHorizontal) { + sizeC.x += 0.75; // Otherwise Firefox and Safari show seams + } + + if (tile.isBottomMost && tiledImage.wrapVertical) { + sizeC.y += 0.75; // Otherwise Firefox and Safari show seams + } + + tile.position = positionC; + tile.size = sizeC; + tile.squaredDistance = tileSquaredDistance; + tile.visibility = levelVisibility; +} + +/** + * @private + * @inner + * Updates the opacity of a tile according to the time it has been on screen + * to perform a fade-in. + * Updates coverage once a tile is fully opaque. + * Returns whether the fade-in has completed. + * + * @param {OpenSeadragon.TiledImage} tiledImage + * @param {OpenSeadragon.Tile} tile + * @param {Number} x + * @param {Number} y + * @param {Number} level + * @param {Number} levelOpacity + * @param {Number} currentTime + * @returns {Boolean} + */ +function blendTile( tiledImage, tile, x, y, level, levelOpacity, currentTime ){ + var blendTimeMillis = 1000 * tiledImage.blendTime, + deltaTime, + opacity; + + if ( !tile.blendStart ) { + tile.blendStart = currentTime; + } + + deltaTime = currentTime - tile.blendStart; + opacity = blendTimeMillis ? Math.min( 1, deltaTime / ( blendTimeMillis ) ) : 1; + + if ( tiledImage.alwaysBlend ) { + opacity *= levelOpacity; + } + + tile.opacity = opacity; + + tiledImage.lastDrawn.push( tile ); + + if ( opacity == 1 ) { + setCoverage( tiledImage.coverage, level, x, y, true ); + tiledImage._hasOpaqueTile = true; + } else if ( deltaTime < blendTimeMillis ) { + return true; + } + + return false; +} + +/** + * @private + * @inner + * Returns true if the given tile provides coverage to lower-level tiles of + * lower resolution representing the same content. If neither x nor y is + * given, returns true if the entire visible level provides coverage. + * + * Note that out-of-bounds tiles provide coverage in this sense, since + * there's no content that they would need to cover. Tiles at non-existent + * levels that are within the image bounds, however, do not. + * + * @param {Object} coverage - A '3d' dictionary [level][x][y] --> Boolean. + * @param {Number} level - The resolution level of the tile. + * @param {Number} x - The X position of the tile. + * @param {Number} y - The Y position of the tile. + * @returns {Boolean} + */ +function providesCoverage( coverage, level, x, y ) { + var rows, + cols, + i, j; + + if ( !coverage[ level ] ) { + return false; + } + + if ( x === undefined || y === undefined ) { + rows = coverage[ level ]; + for ( i in rows ) { + if ( rows.hasOwnProperty( i ) ) { + cols = rows[ i ]; + for ( j in cols ) { + if ( cols.hasOwnProperty( j ) && !cols[ j ] ) { + return false; + } + } + } + } + + return true; + } + + return ( + coverage[ level ][ x] === undefined || + coverage[ level ][ x ][ y ] === undefined || + coverage[ level ][ x ][ y ] === true + ); +} + +/** + * @private + * @inner + * Returns true if the given tile is completely covered by higher-level + * tiles of higher resolution representing the same content. If neither x + * nor y is given, returns true if the entire visible level is covered. + * + * @param {Object} coverage - A '3d' dictionary [level][x][y] --> Boolean. + * @param {Number} level - The resolution level of the tile. + * @param {Number} x - The X position of the tile. + * @param {Number} y - The Y position of the tile. + * @returns {Boolean} + */ +function isCovered( coverage, level, x, y ) { + if ( x === undefined || y === undefined ) { + return providesCoverage( coverage, level + 1 ); + } else { + return ( + providesCoverage( coverage, level + 1, 2 * x, 2 * y ) && + providesCoverage( coverage, level + 1, 2 * x, 2 * y + 1 ) && + providesCoverage( coverage, level + 1, 2 * x + 1, 2 * y ) && + providesCoverage( coverage, level + 1, 2 * x + 1, 2 * y + 1 ) + ); + } +} + +/** + * @private + * @inner + * Sets whether the given tile provides coverage or not. + * + * @param {Object} coverage - A '3d' dictionary [level][x][y] --> Boolean. + * @param {Number} level - The resolution level of the tile. + * @param {Number} x - The X position of the tile. + * @param {Number} y - The Y position of the tile. + * @param {Boolean} covers - Whether the tile provides coverage. + */ +function setCoverage( coverage, level, x, y, covers ) { + if ( !coverage[ level ] ) { + $.console.warn( + "Setting coverage for a tile before its level's coverage has been reset: %s", + level + ); + return; + } + + if ( !coverage[ level ][ x ] ) { + coverage[ level ][ x ] = {}; + } + + coverage[ level ][ x ][ y ] = covers; +} + +/** + * @private + * @inner + * Resets coverage information for the given level. This should be called + * after every draw routine. Note that at the beginning of the next draw + * routine, coverage for every visible tile should be explicitly set. + * + * @param {Object} coverage - A '3d' dictionary [level][x][y] --> Boolean. + * @param {Number} level - The resolution level of tiles to completely reset. + */ +function resetCoverage( coverage, level ) { + coverage[ level ] = {}; +} + +/** + * @private + * @inner + * Determines whether the 'last best' tile for the area is better than the + * tile in question. + * + * @param {OpenSeadragon.Tile} previousBest + * @param {OpenSeadragon.Tile} tile + * @returns {OpenSeadragon.Tile} The new best tile. + */ +function compareTiles( previousBest, tile ) { + if ( !previousBest ) { + return tile; + } + + if ( tile.visibility > previousBest.visibility ) { + return tile; + } else if ( tile.visibility == previousBest.visibility ) { + if ( tile.squaredDistance < previousBest.squaredDistance ) { + return tile; + } + } + + return previousBest; +} + +/** + * @private + * @inner + * Draws a TiledImage. + * @param {OpenSeadragon.TiledImage} tiledImage + * @param {OpenSeadragon.Tile[]} lastDrawn - An unordered list of Tiles drawn last frame. + */ +function drawTiles( tiledImage, lastDrawn ) { + if (tiledImage.opacity === 0 || (lastDrawn.length === 0 && !tiledImage.placeholderFillStyle)) { + return; + } + + var tile = lastDrawn[0]; + var useSketch; + + if (tile) { + useSketch = tiledImage.opacity < 1 || + (tiledImage.compositeOperation && + tiledImage.compositeOperation !== 'source-over') || + (!tiledImage._isBottomItem() && tile._hasTransparencyChannel()); + } + + var sketchScale; + var sketchTranslate; + + var zoom = tiledImage.viewport.getZoom(true); + var imageZoom = tiledImage.viewportToImageZoom(zoom); + + if (lastDrawn.length > 1 && + imageZoom > tiledImage.smoothTileEdgesMinZoom && + !tiledImage.iOSDevice && + tiledImage.getRotation(true) % 360 === 0 && // TODO: support tile edge smoothing with tiled image rotation. + $.supportsCanvas) { + // When zoomed in a lot (>100%) the tile edges are visible. + // So we have to composite them at ~100% and scale them up together. + // Note: Disabled on iOS devices per default as it causes a native crash + useSketch = true; + sketchScale = tile.getScaleForEdgeSmoothing(); + sketchTranslate = tile.getTranslationForEdgeSmoothing(sketchScale, + tiledImage._drawer.getCanvasSize(false), + tiledImage._drawer.getCanvasSize(true)); + } + + var bounds; + if (useSketch) { + if (!sketchScale) { + // Except when edge smoothing, we only clean the part of the + // sketch canvas we are going to use for performance reasons. + bounds = tiledImage.viewport.viewportToViewerElementRectangle( + tiledImage.getClippedBounds(true)) + .getIntegerBoundingBox() + .times($.pixelDensityRatio); + } + tiledImage._drawer._clear(true, bounds); + } + + // When scaling, we must rotate only when blending the sketch canvas to + // avoid interpolation + if (!sketchScale) { + if (tiledImage.viewport.degrees !== 0) { + tiledImage._drawer._offsetForRotation({ + degrees: tiledImage.viewport.degrees, + useSketch: useSketch + }); + } + if (tiledImage.getRotation(true) % 360 !== 0) { + tiledImage._drawer._offsetForRotation({ + degrees: tiledImage.getRotation(true), + point: tiledImage.viewport.pixelFromPointNoRotate( + tiledImage._getRotationPoint(true), true), + useSketch: useSketch + }); + } + } + + var usedClip = false; + if ( tiledImage._clip ) { + tiledImage._drawer.saveContext(useSketch); + + var box = tiledImage.imageToViewportRectangle(tiledImage._clip, true); + box = box.rotate(-tiledImage.getRotation(true), tiledImage._getRotationPoint(true)); + var clipRect = tiledImage._drawer.viewportToDrawerRectangle(box); + if (sketchScale) { + clipRect = clipRect.times(sketchScale); + } + if (sketchTranslate) { + clipRect = clipRect.translate(sketchTranslate); + } + tiledImage._drawer.setClip(clipRect, useSketch); + + usedClip = true; + } + + if ( tiledImage.placeholderFillStyle && tiledImage._hasOpaqueTile === false ) { + var placeholderRect = tiledImage._drawer.viewportToDrawerRectangle(tiledImage.getBounds(true)); + if (sketchScale) { + placeholderRect = placeholderRect.times(sketchScale); + } + if (sketchTranslate) { + placeholderRect = placeholderRect.translate(sketchTranslate); + } + + var fillStyle = null; + if ( typeof tiledImage.placeholderFillStyle === "function" ) { + fillStyle = tiledImage.placeholderFillStyle(tiledImage, tiledImage._drawer.context); + } + else { + fillStyle = tiledImage.placeholderFillStyle; + } + + tiledImage._drawer.drawRectangle(placeholderRect, fillStyle, useSketch); + } + + for (var i = lastDrawn.length - 1; i >= 0; i--) { + tile = lastDrawn[ i ]; + tiledImage._drawer.drawTile( tile, tiledImage._drawingHandler, useSketch, sketchScale, sketchTranslate ); + tile.beingDrawn = true; + + if( tiledImage.viewer ){ + /** + * - Needs documentation - + * + * @event tile-drawn + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn. + * @property {OpenSeadragon.Tile} tile + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + tiledImage.viewer.raiseEvent( 'tile-drawn', { + tiledImage: tiledImage, + tile: tile + }); + } + } + + if ( usedClip ) { + tiledImage._drawer.restoreContext( useSketch ); + } + + if (!sketchScale) { + if (tiledImage.getRotation(true) % 360 !== 0) { + tiledImage._drawer._restoreRotationChanges(useSketch); + } + if (tiledImage.viewport.degrees !== 0) { + tiledImage._drawer._restoreRotationChanges(useSketch); + } + } + + if (useSketch) { + if (sketchScale) { + if (tiledImage.viewport.degrees !== 0) { + tiledImage._drawer._offsetForRotation({ + degrees: tiledImage.viewport.degrees, + useSketch: false + }); + } + if (tiledImage.getRotation(true) % 360 !== 0) { + tiledImage._drawer._offsetForRotation({ + degrees: tiledImage.getRotation(true), + point: tiledImage.viewport.pixelFromPointNoRotate( + tiledImage._getRotationPoint(true), true), + useSketch: false + }); + } + } + tiledImage._drawer.blendSketch({ + opacity: tiledImage.opacity, + scale: sketchScale, + translate: sketchTranslate, + compositeOperation: tiledImage.compositeOperation, + bounds: bounds + }); + if (sketchScale) { + if (tiledImage.getRotation(true) % 360 !== 0) { + tiledImage._drawer._restoreRotationChanges(false); + } + if (tiledImage.viewport.degrees !== 0) { + tiledImage._drawer._restoreRotationChanges(false); + } + } + } + drawDebugInfo( tiledImage, lastDrawn ); +} + +/** + * @private + * @inner + * Draws special debug information for a TiledImage if in debug mode. + * @param {OpenSeadragon.TiledImage} tiledImage + * @param {OpenSeadragon.Tile[]} lastDrawn - An unordered list of Tiles drawn last frame. + */ +function drawDebugInfo( tiledImage, lastDrawn ) { + if( tiledImage.debugMode ) { + for ( var i = lastDrawn.length - 1; i >= 0; i-- ) { + var tile = lastDrawn[ i ]; + try { + tiledImage._drawer.drawDebugInfo( + tile, lastDrawn.length, i, tiledImage); + } catch(e) { + $.console.error(e); + } + } + } +} + +}( OpenSeadragon )); + +/* + * OpenSeadragon - TileCache + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +// private class +var TileRecord = function( options ) { + $.console.assert( options, "[TileCache.cacheTile] options is required" ); + $.console.assert( options.tile, "[TileCache.cacheTile] options.tile is required" ); + $.console.assert( options.tiledImage, "[TileCache.cacheTile] options.tiledImage is required" ); + this.tile = options.tile; + this.tiledImage = options.tiledImage; +}; + +// private class +var ImageRecord = function(options) { + $.console.assert( options, "[ImageRecord] options is required" ); + $.console.assert( options.image, "[ImageRecord] options.image is required" ); + this._image = options.image; + this._tiles = []; +}; + +ImageRecord.prototype = { + destroy: function() { + this._image = null; + this._renderedContext = null; + this._tiles = null; + }, + + getImage: function() { + return this._image; + }, + + getRenderedContext: function() { + if (!this._renderedContext) { + var canvas = document.createElement( 'canvas' ); + canvas.width = this._image.width; + canvas.height = this._image.height; + this._renderedContext = canvas.getContext('2d'); + this._renderedContext.drawImage( this._image, 0, 0 ); + //since we are caching the prerendered image on a canvas + //allow the image to not be held in memory + this._image = null; + } + return this._renderedContext; + }, + + setRenderedContext: function(renderedContext) { + $.console.error("ImageRecord.setRenderedContext is deprecated. " + + "The rendered context should be created by the ImageRecord " + + "itself when calling ImageRecord.getRenderedContext."); + this._renderedContext = renderedContext; + }, + + addTile: function(tile) { + $.console.assert(tile, '[ImageRecord.addTile] tile is required'); + this._tiles.push(tile); + }, + + removeTile: function(tile) { + for (var i = 0; i < this._tiles.length; i++) { + if (this._tiles[i] === tile) { + this._tiles.splice(i, 1); + return; + } + } + + $.console.warn('[ImageRecord.removeTile] trying to remove unknown tile', tile); + }, + + getTileCount: function() { + return this._tiles.length; + } +}; + +/** + * @class TileCache + * @memberof OpenSeadragon + * @classdesc Stores all the tiles displayed in a {@link OpenSeadragon.Viewer}. + * You generally won't have to interact with the TileCache directly. + * @param {Object} options - Configuration for this TileCache. + * @param {Number} [options.maxImageCacheCount] - See maxImageCacheCount in + * {@link OpenSeadragon.Options} for details. + */ +$.TileCache = function( options ) { + options = options || {}; + + this._maxImageCacheCount = options.maxImageCacheCount || $.DEFAULT_SETTINGS.maxImageCacheCount; + this._tilesLoaded = []; + this._imagesLoaded = []; + this._imagesLoadedCount = 0; +}; + +/** @lends OpenSeadragon.TileCache.prototype */ +$.TileCache.prototype = { + /** + * @returns {Number} The total number of tiles that have been loaded by + * this TileCache. + */ + numTilesLoaded: function() { + return this._tilesLoaded.length; + }, + + /** + * Caches the specified tile, removing an old tile if necessary to stay under the + * maxImageCacheCount specified on construction. Note that if multiple tiles reference + * the same image, there may be more tiles than maxImageCacheCount; the goal is to keep + * the number of images below that number. Note, as well, that even the number of images + * may temporarily surpass that number, but should eventually come back down to the max specified. + * @param {Object} options - Tile info. + * @param {OpenSeadragon.Tile} options.tile - The tile to cache. + * @param {String} options.tile.cacheKey - The unique key used to identify this tile in the cache. + * @param {Image} options.image - The image of the tile to cache. + * @param {OpenSeadragon.TiledImage} options.tiledImage - The TiledImage that owns that tile. + * @param {Number} [options.cutoff=0] - If adding this tile goes over the cache max count, this + * function will release an old tile. The cutoff option specifies a tile level at or below which + * tiles will not be released. + */ + cacheTile: function( options ) { + $.console.assert( options, "[TileCache.cacheTile] options is required" ); + $.console.assert( options.tile, "[TileCache.cacheTile] options.tile is required" ); + $.console.assert( options.tile.cacheKey, "[TileCache.cacheTile] options.tile.cacheKey is required" ); + $.console.assert( options.tiledImage, "[TileCache.cacheTile] options.tiledImage is required" ); + + var cutoff = options.cutoff || 0; + var insertionIndex = this._tilesLoaded.length; + + var imageRecord = this._imagesLoaded[options.tile.cacheKey]; + if (!imageRecord) { + $.console.assert( options.image, "[TileCache.cacheTile] options.image is required to create an ImageRecord" ); + imageRecord = this._imagesLoaded[options.tile.cacheKey] = new ImageRecord({ + image: options.image + }); + + this._imagesLoadedCount++; + } + + imageRecord.addTile(options.tile); + options.tile.cacheImageRecord = imageRecord; + + // Note that just because we're unloading a tile doesn't necessarily mean + // we're unloading an image. With repeated calls it should sort itself out, though. + if ( this._imagesLoadedCount > this._maxImageCacheCount ) { + var worstTile = null; + var worstTileIndex = -1; + var worstTileRecord = null; + var prevTile, worstTime, worstLevel, prevTime, prevLevel, prevTileRecord; + + for ( var i = this._tilesLoaded.length - 1; i >= 0; i-- ) { + prevTileRecord = this._tilesLoaded[ i ]; + prevTile = prevTileRecord.tile; + + if ( prevTile.level <= cutoff || prevTile.beingDrawn ) { + continue; + } else if ( !worstTile ) { + worstTile = prevTile; + worstTileIndex = i; + worstTileRecord = prevTileRecord; + continue; + } + + prevTime = prevTile.lastTouchTime; + worstTime = worstTile.lastTouchTime; + prevLevel = prevTile.level; + worstLevel = worstTile.level; + + if ( prevTime < worstTime || + ( prevTime == worstTime && prevLevel > worstLevel ) ) { + worstTile = prevTile; + worstTileIndex = i; + worstTileRecord = prevTileRecord; + } + } + + if ( worstTile && worstTileIndex >= 0 ) { + this._unloadTile(worstTileRecord); + insertionIndex = worstTileIndex; + } + } + + this._tilesLoaded[ insertionIndex ] = new TileRecord({ + tile: options.tile, + tiledImage: options.tiledImage + }); + }, + + /** + * Clears all tiles associated with the specified tiledImage. + * @param {OpenSeadragon.TiledImage} tiledImage + */ + clearTilesFor: function( tiledImage ) { + $.console.assert(tiledImage, '[TileCache.clearTilesFor] tiledImage is required'); + var tileRecord; + for ( var i = 0; i < this._tilesLoaded.length; ++i ) { + tileRecord = this._tilesLoaded[ i ]; + if ( tileRecord.tiledImage === tiledImage ) { + this._unloadTile(tileRecord); + this._tilesLoaded.splice( i, 1 ); + i--; + } + } + }, + + // private + getImageRecord: function(cacheKey) { + $.console.assert(cacheKey, '[TileCache.getImageRecord] cacheKey is required'); + return this._imagesLoaded[cacheKey]; + }, + + // private + _unloadTile: function(tileRecord) { + $.console.assert(tileRecord, '[TileCache._unloadTile] tileRecord is required'); + var tile = tileRecord.tile; + var tiledImage = tileRecord.tiledImage; + + tile.unload(); + tile.cacheImageRecord = null; + + var imageRecord = this._imagesLoaded[tile.cacheKey]; + imageRecord.removeTile(tile); + if (!imageRecord.getTileCount()) { + imageRecord.destroy(); + delete this._imagesLoaded[tile.cacheKey]; + this._imagesLoadedCount--; + } + + /** + * Triggered when a tile has just been unloaded from memory. + * + * @event tile-unloaded + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image of the unloaded tile. + * @property {OpenSeadragon.Tile} tile - The tile which has been unloaded. + */ + tiledImage.viewer.raiseEvent("tile-unloaded", { + tile: tile, + tiledImage: tiledImage + }); + } +}; + +}( OpenSeadragon )); + +/* + * OpenSeadragon - World + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class World + * @memberof OpenSeadragon + * @extends OpenSeadragon.EventSource + * @classdesc Keeps track of all of the tiled images in the scene. + * @param {Object} options - World options. + * @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this World. + **/ +$.World = function( options ) { + var _this = this; + + $.console.assert( options.viewer, "[World] options.viewer is required" ); + + $.EventSource.call( this ); + + this.viewer = options.viewer; + this._items = []; + this._needsDraw = false; + this._autoRefigureSizes = true; + this._needsSizesFigured = false; + this._delegatedFigureSizes = function(event) { + if (_this._autoRefigureSizes) { + _this._figureSizes(); + } else { + _this._needsSizesFigured = true; + } + }; + + this._figureSizes(); +}; + +$.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.World.prototype */{ + /** + * Add the specified item. + * @param {OpenSeadragon.TiledImage} item - The item to add. + * @param {Number} [options.index] - Index for the item. If not specified, goes at the top. + * @fires OpenSeadragon.World.event:add-item + * @fires OpenSeadragon.World.event:metrics-change + */ + addItem: function( item, options ) { + $.console.assert(item, "[World.addItem] item is required"); + $.console.assert(item instanceof $.TiledImage, "[World.addItem] only TiledImages supported at this time"); + + options = options || {}; + if (options.index !== undefined) { + var index = Math.max(0, Math.min(this._items.length, options.index)); + this._items.splice(index, 0, item); + } else { + this._items.push( item ); + } + + if (this._autoRefigureSizes) { + this._figureSizes(); + } else { + this._needsSizesFigured = true; + } + + this._needsDraw = true; + + item.addHandler('bounds-change', this._delegatedFigureSizes); + item.addHandler('clip-change', this._delegatedFigureSizes); + + /** + * Raised when an item is added to the World. + * @event add-item + * @memberOf OpenSeadragon.World + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the World which raised the event. + * @property {OpenSeadragon.TiledImage} item - The item that has been added. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'add-item', { + item: item + } ); + }, + + /** + * Get the item at the specified index. + * @param {Number} index - The item's index. + * @returns {OpenSeadragon.TiledImage} The item at the specified index. + */ + getItemAt: function( index ) { + $.console.assert(index !== undefined, "[World.getItemAt] index is required"); + return this._items[ index ]; + }, + + /** + * Get the index of the given item or -1 if not present. + * @param {OpenSeadragon.TiledImage} item - The item. + * @returns {Number} The index of the item or -1 if not present. + */ + getIndexOfItem: function( item ) { + $.console.assert(item, "[World.getIndexOfItem] item is required"); + return $.indexOf( this._items, item ); + }, + + /** + * @returns {Number} The number of items used. + */ + getItemCount: function() { + return this._items.length; + }, + + /** + * Change the index of a item so that it appears over or under others. + * @param {OpenSeadragon.TiledImage} item - The item to move. + * @param {Number} index - The new index. + * @fires OpenSeadragon.World.event:item-index-change + */ + setItemIndex: function( item, index ) { + $.console.assert(item, "[World.setItemIndex] item is required"); + $.console.assert(index !== undefined, "[World.setItemIndex] index is required"); + + var oldIndex = this.getIndexOfItem( item ); + + if ( index >= this._items.length ) { + throw new Error( "Index bigger than number of layers." ); + } + + if ( index === oldIndex || oldIndex === -1 ) { + return; + } + + this._items.splice( oldIndex, 1 ); + this._items.splice( index, 0, item ); + this._needsDraw = true; + + /** + * Raised when the order of the indexes has been changed. + * @event item-index-change + * @memberOf OpenSeadragon.World + * @type {object} + * @property {OpenSeadragon.World} eventSource - A reference to the World which raised the event. + * @property {OpenSeadragon.TiledImage} item - The item whose index has + * been changed + * @property {Number} previousIndex - The previous index of the item + * @property {Number} newIndex - The new index of the item + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'item-index-change', { + item: item, + previousIndex: oldIndex, + newIndex: index + } ); + }, + + /** + * Remove an item. + * @param {OpenSeadragon.TiledImage} item - The item to remove. + * @fires OpenSeadragon.World.event:remove-item + * @fires OpenSeadragon.World.event:metrics-change + */ + removeItem: function( item ) { + $.console.assert(item, "[World.removeItem] item is required"); + + var index = $.indexOf(this._items, item ); + if ( index === -1 ) { + return; + } + + item.removeHandler('bounds-change', this._delegatedFigureSizes); + item.removeHandler('clip-change', this._delegatedFigureSizes); + item.destroy(); + this._items.splice( index, 1 ); + this._figureSizes(); + this._needsDraw = true; + this._raiseRemoveItem(item); + }, + + /** + * Remove all items. + * @fires OpenSeadragon.World.event:remove-item + * @fires OpenSeadragon.World.event:metrics-change + */ + removeAll: function() { + // We need to make sure any pending images are canceled so the world items don't get messed up + this.viewer._cancelPendingImages(); + var item; + var i; + for (i = 0; i < this._items.length; i++) { + item = this._items[i]; + item.removeHandler('bounds-change', this._delegatedFigureSizes); + item.removeHandler('clip-change', this._delegatedFigureSizes); + item.destroy(); + } + + var removedItems = this._items; + this._items = []; + this._figureSizes(); + this._needsDraw = true; + + for (i = 0; i < removedItems.length; i++) { + item = removedItems[i]; + this._raiseRemoveItem(item); + } + }, + + /** + * Clears all tiles and triggers updates for all items. + */ + resetItems: function() { + for ( var i = 0; i < this._items.length; i++ ) { + this._items[i].reset(); + } + }, + + /** + * Updates (i.e. animates bounds of) all items. + */ + update: function() { + var animated = false; + for ( var i = 0; i < this._items.length; i++ ) { + animated = this._items[i].update() || animated; + } + + return animated; + }, + + /** + * Draws all items. + */ + draw: function() { + for ( var i = 0; i < this._items.length; i++ ) { + this._items[i].draw(); + } + + this._needsDraw = false; + }, + + /** + * @returns {Boolean} true if any items need updating. + */ + needsDraw: function() { + for ( var i = 0; i < this._items.length; i++ ) { + if ( this._items[i].needsDraw() ) { + return true; + } + } + return this._needsDraw; + }, + + /** + * @returns {OpenSeadragon.Rect} The smallest rectangle that encloses all items, in viewport coordinates. + */ + getHomeBounds: function() { + return this._homeBounds.clone(); + }, + + /** + * To facilitate zoom constraints, we keep track of the pixel density of the + * densest item in the World (i.e. the item whose content size to viewport size + * ratio is the highest) and save it as this "content factor". + * @returns {Number} the number of content units per viewport unit. + */ + getContentFactor: function() { + return this._contentFactor; + }, + + /** + * As a performance optimization, setting this flag to false allows the bounds-change event handler + * on tiledImages to skip calculations on the world bounds. If a lot of images are going to be positioned in + * rapid succession, this is a good idea. When finished, setAutoRefigureSizes should be called with true + * or the system may behave oddly. + * @param {Boolean} [value] The value to which to set the flag. + */ + setAutoRefigureSizes: function(value) { + this._autoRefigureSizes = value; + if (value & this._needsSizesFigured) { + this._figureSizes(); + this._needsSizesFigured = false; + } + }, + + /** + * Arranges all of the TiledImages with the specified settings. + * @param {Object} options - Specifies how to arrange. + * @param {Boolean} [options.immediately=false] - Whether to animate to the new arrangement. + * @param {String} [options.layout] - See collectionLayout in {@link OpenSeadragon.Options}. + * @param {Number} [options.rows] - See collectionRows in {@link OpenSeadragon.Options}. + * @param {Number} [options.columns] - See collectionColumns in {@link OpenSeadragon.Options}. + * @param {Number} [options.tileSize] - See collectionTileSize in {@link OpenSeadragon.Options}. + * @param {Number} [options.tileMargin] - See collectionTileMargin in {@link OpenSeadragon.Options}. + * @fires OpenSeadragon.World.event:metrics-change + */ + arrange: function(options) { + options = options || {}; + var immediately = options.immediately || false; + var layout = options.layout || $.DEFAULT_SETTINGS.collectionLayout; + var rows = options.rows || $.DEFAULT_SETTINGS.collectionRows; + var columns = options.columns || $.DEFAULT_SETTINGS.collectionColumns; + var tileSize = options.tileSize || $.DEFAULT_SETTINGS.collectionTileSize; + var tileMargin = options.tileMargin || $.DEFAULT_SETTINGS.collectionTileMargin; + var increment = tileSize + tileMargin; + var wrap; + if (!options.rows && columns) { + wrap = columns; + } else { + wrap = Math.ceil(this._items.length / rows); + } + var x = 0; + var y = 0; + var item, box, width, height, position; + + this.setAutoRefigureSizes(false); + for (var i = 0; i < this._items.length; i++) { + if (i && (i % wrap) === 0) { + if (layout === 'horizontal') { + y += increment; + x = 0; + } else { + x += increment; + y = 0; + } + } + + item = this._items[i]; + box = item.getBounds(); + if (box.width > box.height) { + width = tileSize; + } else { + width = tileSize * (box.width / box.height); + } + + height = width * (box.height / box.width); + position = new $.Point(x + ((tileSize - width) / 2), + y + ((tileSize - height) / 2)); + + item.setPosition(position, immediately); + item.setWidth(width, immediately); + + if (layout === 'horizontal') { + x += increment; + } else { + y += increment; + } + } + this.setAutoRefigureSizes(true); + }, + + // private + _figureSizes: function() { + var oldHomeBounds = this._homeBounds ? this._homeBounds.clone() : null; + var oldContentSize = this._contentSize ? this._contentSize.clone() : null; + var oldContentFactor = this._contentFactor || 0; + + if (!this._items.length) { + this._homeBounds = new $.Rect(0, 0, 1, 1); + this._contentSize = new $.Point(1, 1); + this._contentFactor = 1; + } else { + var item = this._items[0]; + var bounds = item.getBounds(); + this._contentFactor = item.getContentSize().x / bounds.width; + var clippedBounds = item.getClippedBounds().getBoundingBox(); + var left = clippedBounds.x; + var top = clippedBounds.y; + var right = clippedBounds.x + clippedBounds.width; + var bottom = clippedBounds.y + clippedBounds.height; + for (var i = 1; i < this._items.length; i++) { + item = this._items[i]; + bounds = item.getBounds(); + this._contentFactor = Math.max(this._contentFactor, + item.getContentSize().x / bounds.width); + clippedBounds = item.getClippedBounds().getBoundingBox(); + left = Math.min(left, clippedBounds.x); + top = Math.min(top, clippedBounds.y); + right = Math.max(right, clippedBounds.x + clippedBounds.width); + bottom = Math.max(bottom, clippedBounds.y + clippedBounds.height); + } + + this._homeBounds = new $.Rect(left, top, right - left, bottom - top); + this._contentSize = new $.Point( + this._homeBounds.width * this._contentFactor, + this._homeBounds.height * this._contentFactor); + } + + if (this._contentFactor !== oldContentFactor || + !this._homeBounds.equals(oldHomeBounds) || + !this._contentSize.equals(oldContentSize)) { + /** + * Raised when the home bounds or content factor change. + * @event metrics-change + * @memberOf OpenSeadragon.World + * @type {object} + * @property {OpenSeadragon.World} eventSource - A reference to the World which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('metrics-change', {}); + } + }, + + // private + _raiseRemoveItem: function(item) { + /** + * Raised when an item is removed. + * @event remove-item + * @memberOf OpenSeadragon.World + * @type {object} + * @property {OpenSeadragon.World} eventSource - A reference to the World which raised the event. + * @property {OpenSeadragon.TiledImage} item - The item's underlying item. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'remove-item', { item: item } ); + } +}); + +}( OpenSeadragon )); + +//# sourceMappingURL=openseadragon.js.map \ No newline at end of file diff --git a/js/openseadragon/openseadragon-bin-2.0.0/LICENSE.txt b/js/openseadragon/openseadragon-bin-2.0.0/LICENSE.txt new file mode 100644 index 000000000..d4e256082 --- /dev/null +++ b/js/openseadragon/openseadragon-bin-2.0.0/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright (C) 2009 CodePlex Foundation +Copyright (C) 2010-2013 OpenSeadragon contributors + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +- Neither the name of CodePlex Foundation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/js/openseadragon/openseadragon-bin-2.0.0/changelog.txt b/js/openseadragon/openseadragon-bin-2.0.0/changelog.txt new file mode 100644 index 000000000..dc7166b7c --- /dev/null +++ b/js/openseadragon/openseadragon-bin-2.0.0/changelog.txt @@ -0,0 +1,323 @@ +OPENSEADRAGON CHANGELOG +======================= + +2.0.0: + +* True multi-image mode (#450) + * BREAKING CHANGE: Passing an array for the tileSources option is no longer enough to trigger sequence mode; you have to set the sequenceMode option to true as well + * BREAKING CHANGE: Navigator no longer sends an open event when its viewer opens + * BREAKING CHANGE: Viewer.drawers and Viewer.drawersContainer no longer exist + * BREAKING CHANGE: A Viewer's Drawer and Viewport are now made once per Viewer and reused for every image that Viewer opens (rather than being recreated for every open); this means if you change Viewer options between opens, the behavior is different now. + * DEPRECATION: use Viewer.addTiledImage instead of Viewer.addLayer + * addTiledImage supports positioning config properties + * DEPRECATION: use World.getItemAt instead of Viewer.getLayerAtLevel + * DEPRECATION: use World.getIndexOfItem instead of Viewer.getLevelOfLayer + * DEPRECATION: use World.getItemCount instead of Viewer.getLayersCount + * DEPRECATION: use World.setItemIndex instead of Viewer.setLayerLevel + * DEPRECATION: use World.removeItem instead of Viewer.removeLayer + * DEPRECATION: use World.needsDraw instead of Drawer.needsUpdate + * DEPRECATION: use TileCache.numTilesLoaded instead of Drawer.numTilesLoaded + * DEPRECATION: use World.resetItems instead of Drawer.reset + * DEPRECATION: use Drawer.clear and World.draw instead of Drawer.update + * DEPRECATION: the layersAspectRatioEpsilon option is no longer necessary + * DEPRECATION: Viewer's add-layer event is now World's add-item event + * DEPRECATION: Viewer's layer-level-changed event is now World's item-index-change event + * DEPRECATION: Viewer's remove-layer event is now World's remove-item event + * DEPRECATION: Viewer's add-layer-failed event is now add-item-failed + * DEPRECATION: TileSourceCollection has been retired in favor of World + * DEPRECATION: collectionMode no longer draws outlines or reflections for items + * Drawer has been split into three classes: + * TiledImage, tile management and positioning for a single tiled image + * TileCache, tile caching for all images + * Drawer, tile drawing for all images + * New class: World, keeps track of multiple images in the scene + * Viewer now has world and tileCache properties + * Rect and Point now have clone functions + * New Viewport method for managing homeBounds as well as constraints: setHomeBounds + * Viewport.open supports positioning config properties + * For multi-image open, drawing isn't started until all tileSources have been opened + * You can specify a clip area for each image (only works on browsers that support the HTML5 canvas) (#594) + * Added placeholderFillStyle so image rectangles can be drawn even before their tiles load (#635) + * Ability to set opacity on individual TiledImages (#644) +* Margins option to push the home region in from the edges of the Viewer (#505) +* Rect and Point toString() functions are now consistent: rounding values to nearest hundredth +* Overlays appear in the DOM immediately on open or addOverlay (#507) +* imageLoaderLimit now works (#544) +* Turning off scrollToZoom in gestureSettings now allows scroll events to propagate +* You can now set a minZoomLevel that's greater than the home zoom level +* Added union() to OpenSeadragon.Rect +* Fixed an error in fitBounds if the new and old bounds were extremely close in size +* Added ajaxWithCredentials option (#543) +* Added viewport-change event for after the viewport changes but before it's drawn +* A spring's current value is now updated immediately on reset (#524) +* Fixed an error in fitBounds that occurred sometimes with immediately = true +* Added support for HDPI (retina) displays (#583) +* Corrected IIIF tile source to use canonical syntax (#586) +* Fixed x/y typo that caused horizontal reference strip to be rendered only relative to height (#595) +* Fixed Firefox 35 not able to open local files (#588) +* Fixed an issue with zero size viewers in IE8 (#609) +* Fixed: Cross Origin policy not working (#613) +* Optimized tile loading by clearing the queue on a re-draw when imageLoaderLimit is set (#616) +* Now animating zoom spring exponentially (#631) +* Added http://editorconfig.org/ config file (#637) +* Keyboard pan speed is now the same regardless of zoom level (#645) + +1.2.1: + +* Added preserveOverlays option (#561) +* Fixed: DZI tilesource was broken on IE8/IE9 (#563) +* Exposed secondary pointer button (middle, right, etc.) events from MouseTracker and through viewer (#479) +* MouseTracker - Improved IE 8 compatibility (#562) +* MouseTracker - Improved IE 9+ compatibility (#564) +* MouseTracker - Simulated touchenter/touchleave events now bubble to parent element MouseTrackers (#566) +* MouseTracker - Improved multitouch support in enter/exit event handlers (#566) +* MouseTracker - orphaned tracked touch pointers removed (fix for #539) +* MouseTracker - removed touchenter/touchleave event support since the events don't exist on any known platform and have been removed from the W3C specification (#566) +* Removed Viewer onContainerPress/onContainerRelease handlers (and the associated 'container-release' event ) that were never fired due to the canvas (child) element capturing the DOM events (#566) +* Added 'canvas-enter', 'canvas-exit', and 'canvas-press' events to Viewer (#566) +* ButtonGroup - removed obsolete MouseTracker event handlers (#566) +* MouseTracker - added keydown and keyup handlers (#568) +* Modifier keys ignored in keyboard navigation handlers (#503) +* Requesting keyboard focus when viewer is clicked (#537) +* Arrow key navigation fixed across platforms (#565) +* Removed textarea element from viewer DOM. Viewer.canvas now handles keyboard navigation (#569) +* Removed 'position' property from MouseTracker keyDownHandler/keyUpHandler/keyHandler functions (#573) +* Fixed pointer event model detection for IE 10 and IE 11 (#571) +* Added setMouseNavEnabled() support to Navigator (#572) +* MouseTracker now defaults to tracking on (#558) +* Removed Viewer focusHandler/onCanvasFocus (#577) +* Added tabIndex option to viewer (#577) + +1.2.0: + +* New combined IIIF TileSource for 1.0 through 2.0 (#441) + * BREAKING CHANGE: Removed IIIF1_1TileSource (now that IIIFTileSource supports all versions) +* Allowed TileSources to have dynamic tileSize via source.getTileSize(level) (#441) + * DEPRECATION: Use .getTileSize(level) instead of .tileSize +* Fix for IIPServer-style urls when using DZI (#413) +* Fix memory leak while destroying the viewer (#421) +* Added fitBoundsWithConstraints() to the viewport (#423) +* Fixed MouseTracker cross-browser issues with tracking pointers over and out of the tracked element (pull request #448, fix for #152, #404, #420, and #427) +* Fixed incorrect flick direction after image is rotated (#452) +* Debug mode now works with rotate images (#453) +* Now supporting dzi xml with namespaces (#462) +* You can now rotate the navigator along with the main viewer (#455) +* Viewport.setRotation now allows all rotation angles (#466) +* Pinch rotate is now available (defaults to off) (#468) +* Added option for home button to fill viewer (#474) +* Better handling of mid-update image loaded callbacks (#409) +* Tracked pointers are now cleaned up when Viewer.setMouseNavEnabled(false) is called (#518) +* Added explicit pointer capture for touch event model touchstart events (#552) + +1.1.1: + +* Fixed issue with dragging the navigator highlight on Webkit browsers (#395) +* Improved Viewer Options Support in Gesture Handling (#399) + +1.1.0: + +* BREAKING CHANGE: the openseadragon-canvas element now has two child divs. This means: (#298) + * The drawer element is no longer accessible via viewer.canvas.firstChild but via viewer.drawersContainer.firstChild or viewer.drawer.canvas. + * The overlays elements are no longer accessible via viewer.canvas.childNodes but via viewer.overlaysContainer.childNodes or viewer.currentOverlays[i].element. +* BREAKING CHANGE: Pseudo full screen mode on IE<11 using activex has been dropped. OpenSeadragon will run in full page if full screen mode is requested. +* BREAKING CHANGE: MouseTracker touch pinch gestures are no longer converted to scroll events. MouseTracker.pinchHandler should be used instead. (#369) +* DEPRECATION: overlay functions have been moved from Drawer to Viewer (#331) +* DEPRECATION: OpenSeadragon.cancelFullScreen has been renamed OpenSeadragon.exitFullScreen (#358) +* DEPRECATION: The 'isTouchEvent' property passed in MouseTracker events is deprecated and has been replaced with 'pointerType', which is a String value "mouse", "touch", "pen", etc. to support multiple simultaneous pointing devices (#369) +* DEPRECATION: The 'buttonDownAny' property passed in MouseTracker enter and exit events (enterHandler/exitHandler) is deprecated and has been replaced with 'buttons', which indicates the button(s) currently pressed (#369) +* DEPRECATION: The 'buttonDownAny' property passed in Viewer's 'container-enter' and 'container-exit' events is deprecated and has been replaced with 'buttons', which indicates the button(s) currently pressed (#369) +* Added layers support. Multiple images can now been displayed on top of each other with transparency via the Viewer.addLayer method (#298) +* Improved overlay functions (#331) +* Fixed: Nav button highlight states aren't quite aligned on Firefox (#303) +* Added ControlAnchor options for default controls (#304) +* Enabled basic cross-domain tile loading without tainting canvas (works in Chrome and Firefox) (#308) +* Added crossOriginPolicy drawer configuration to enable or disable CORS image requests (#364) +* Disabled CORS by default (#377) +* Added a ControlAnchor.ABSOLUTE enumeration. Enables absolute positioning of control elements in the viewer (#310) +* Added a 'navigator-scroll' event to Navigator. Fired when mousewheel events occur in the navigator (#310) +* Added a navigatorMaintainSizeRatio option. If set to true, the navigator minimap resizes when the viewer element is resized (#310) +* Added 'ABSOLUTE' as a navigatorPosition option, along with corresponding navigatorTop, navigatorLeft options. Allows the navigator minimap to be placed anywhere in the viewer (#310) +* Enhanced the navigatorTop, navigatorLeft, navigatorHeight, and navigatorWidth options to allow a number for pixel units or a string for other element units (%, em, etc.) (#310) +* Additional enhancements for IIIF support (#315) +* Fixed: Setting degrees in Viewer constructor has no effect (#336) +* Added pre-draw event for tiles to allow applications to alter the image (#348) +* Added optional Rotate Left/Right buttons to standard controls (#341) +* Added optimization for large numbers of overlays: `checkResize = false` option for OpenSeadragon.Overlay (#365) +* Updated full screen API, adding support for Opera and IE11 and allowing keyboard input in Chrome (#358) +* Various fixes to bring OpenSeadragon into W3C compliance (#375) +* Added separate flags for turning off each of the nav buttons (#376) +* Added support for query parameters in DZI tileSource URL (#378) +* Enhanced MouseTracker for multi-touch (#369) + * Added support for tracking multiple touch-points on multiple/simultaneous pointing devices + * Added support for the W3C Pointer Events event model. Enables touch/multi-touch on IE10+ + * Added a dragEndHandler event callback, called when a drag gesture ends + * Added a pinchHandler event callback, called as a pinch gesture (2 touch points) is occurring + * Added real-time velocity (speed and direction) tracking to drag operations. 'speed' and 'direction' values are passed in the dragHandler and dragEndHandler event data +* Enhanced Viewer for multi-touch (#369) + * Added pinch zoom with the new MouseTracker pinchHandler. The 'pan' and 'zoom' Viewer events can be used to detect changes resulting in pinch gestures + * Added a "canvas-pinch" event fired by the pinch event handler + * Added flick gesture with the new MouseTracker dragEndHandler + * Added a "canvas-drag-end" event fired by the drag-end event handler + * Added a GestureSettings class for per-device gesture options. Currently has settings to enable/disable zoom-on-scroll, zoom-on-pinch, zoom-on-click, and flick gesture settings. + * Added GestureSettings objects for mouse, touch, and pen devices to the Viewer options giving users the ability to customize gesture handling in the viewer + * Added velocity (speed and direction) properties to the "canvas-drag" event +* Added double-click gesture detection to MouseTracker with corresponding dblClickHandler event callback (#392) +* Added zoom on double-click feature to Viewer, with corresponding dblClickToZoom option added to the GestureSettings class (#392) +* Made it possible to run OpenSeadragon from local filesystem on some browsers (#379) + +1.0.0: + +NOTE: This version has a number of breaking changes to the API, mostly in event handling. See below. + +* BREAKING CHANGE: All EventSource and MouseTracker event handler method signatures changed to 'handlerMethod(event)' where event == { eventSource, userData, ... } (#251) (Also fixes #23, #224, #239) + * The new eventSource property in the event object replaces the old eventSource parameter that was passed to handler methods. + * Where the event object duplicated the eventSource value, those properties have been removed. This affects the following events: + * All Button events - 'button' property removed + * All Viewer (Viewer, Drawer, Viewport) events - 'viewer' property removed +* BREAKING CHANGE: Renamed EventHandler to EventSource (#225) +* BREAKING CHANGE: Event names changed for consistency: changed to lower case, compound names hyphenated, and "on" prefixes removed (#226): + * Viewer "animationstart" changed to "animation-start" + * Viewer "animationfinish" changed to "animation-finish" + * Button "onPress" changed to "press" + * Button "onRelease" changed to "release" + * Button "onClick" changed to "click" + * Button "onEnter" changed to "enter" + * Button "onExit" changed to "exit" + * Button "onFocus" changed to "focus" + * Button "onBlur" changed to "blur" +* BREAKING CHANGE: Numerous improvements to fullPage/fullScreen (#256): + * Retains zoom/pan position better when switching into and out of fullPage. + * Retains scroll position when switching back out. + * More resilient to styling variations on the page. + * setFullPage no longer automatically engages fullScreen; there's now a separate setFullScreen. + * 'fullpage' event is now 'full-page'. + * The `fullpage` property of the 'full-page' event is now `fullPage`. + * There is now a 'full-screen' event with a `fullScreen` property (true if it has gone to full screen). + * There are now 'pre-full-page' and 'pre-full-screen' events that include a `preventDefaultAction` property you can set in your handler to cancel. They also have `fullPage` and `fullScreen` properties respectively, to indicate if they are going into or out of the mode. +* BREAKING CHANGE: Removed the 'onPageChange' callback from the viewer options. Viewer.goToPage() now raises the 'page' event only (#285) +* Major documentation improvements (#281) +* MouseTracker now passes the original event objects to its handler methods (#23) +* MouseTracker now supports an optional 'moveHandler' method for tracking mousemove events (#215) +* Added stopHandler to MouseTracker. (#262) +* Fixed: Element-relative mouse coordinates now correct if the element and/or page is scrolled (using new OpenSeadragon.getElementOffset() method) (#131) +* Fixed: Pinch zoom event issue, regressive issue from previous event system changes (#244) +* Added IIIF Image API 1.1 Tile Source (#230) +* IIIF 1.0 now uses pixel based syntax (#249) +* Fixed: Touch event issue where no canvas-click events were being raised (#240) +* Check that zoom reference point is valid before using it in zoomTo and zoomBy (#247) +* Added a number of easier coordinate conversion methods to viewport (#243) +* Added the ability to create a viewer and start at a specified page (#252) +* Fixed image resolve issue with collection mode (#255) +* DOM events are now passed through as 'event.originalEvent' in viewer and button events where appropriate. (#257) Affects the following events: + * Viewer: 'canvas-release', 'canvas-click', 'canvas-drag', 'canvas-scroll', 'container-enter', 'container-exit', 'container-release' + * Button: 'enter', 'exit', 'press', 'release', 'focus', 'blur', 'click' +* Fixed: IE 10 not reading DZI file correctly in certain circumstances (#218) +* Added support for the 'wheel' DOM mousewheel event (#261) +* Fix for non-canvas tile rendering at large size (#264) +* Drawer now uses an HTML5 canvas element whenever it's available. Can be overridden with the Viewer.useCanvas option (#191) +* Added a boolean preventDefaultAction property (default false) to the event object passed to MouseTracker handler methods. (#270) Implemented in the following MouseTracker subscribers: + * Viewer.keyboardCommandArea.innerTracker.focusHandler: preventDefaultAction == true prevents scrolling viewer into view + * Viewer.keyboardCommandArea.innerTracker.keyHandler: preventDefaultAction == true prevents viewer keyboard navigation + * Viewer.innerTracker.clickHandler: preventDefaultAction == true prevents viewer zoom on click + * Viewer.innerTracker.dragHandler: preventDefaultAction == true prevents viewer panning with mouse/touch + * Viewer.innerTracker.scrollHandler: preventDefaultAction == true prevents viewer zooming on mousewheel/pinch +* Fixed: IE8 error with custom buttons - "Object doesn't support this action" (#279) +* Support IIIF servers that don't report tile dimensions (#286) +* Added an autoResize option. Default is true. When set to false, the viewer takes no action when its container element is resized. (#291) +* Added a static 'version' property to OpenSeadragon. Useful for plugins that require specific OpenSeadragon versions. (#292) + +0.9.131: + +* Fixed: canvas-click event shouldn't fire as you drag (#198) +* Fixed: LegacyTileSource doesn't fail gracefully when no supported file formats are found (#202) +* Added an optional userData argument to EventHandler.addHandler() which is passed unchanged to the handler method (#203) +* Fixed AJAX error reporting on IE8 (#208) +* Added viewportToImageRectangle method, and updated imageToViewportRectangle, imageToViewportCoordinates, and viewportToImageCoordinates to be more flexible with params (#212) +* Fixed: Viewer is not responsive (css) after returning from full screen (#222) + +0.9.130: + +* Added partial support for rotation (just 90 degree increments for now). (#185) +* Hiding and restoring broke the viewer; fixed (#177) +* You can now provide an onDraw function for overlays to do custom overlay manipulation (#160) +* Added a destroy function on the viewer to clean up and remove elements (#179) +* Fixed: navigatorPosition option corrected. (#163) +* OpenSeadragon.now() returned undefined the first time; fixed +* onTouchEnd did not call the correct mouse up handler; fixed (#159) +* Touch events no longer capture mouse (was causing issues on devices that support both) (#168) +* Clicking on a button control no longer refreshes page (#184) +* Drawer now works when the page is rtl (#187) +* Fixed a situation that could throw errors in touch handling (#188) + +0.9.129: + +* Fixed: navigator image not updating when base zoom image is changed (#147) +* Fixed tile rendering issue at lower zoom levels with the IIIF TileSource (#55) +* On IE, ajax errors would cause an exception to be thrown; fixed (#144) +* Faster and more consistent millisecond getter (#138) +* Fixed an error when using navPrevNextWrap on single images (#135) +* Various fixes to our timer handling (#133) +* Now generating source map for openseadragon.min.js (#51) +* Fix for calculating overlay width / height (#142) +* JSHint tidying (#136) +* Improved Ajax method (#149) +* Overhauled AJAX error reporting (#151) + +0.9.128: + +* The navigator is now off by default (#102) +* Reverted minPixelRatio to 0.5 for better quality (#116) +* Sometimes tiles wouldn't resolve if you used the blendTime option; fixed. (#95) +* You can now choose to have previous and next buttons wrap using the config.navPrevNextWrap. (#114) +* You can now specify an ID for a div to hold the navigator (#46) +* You can now click in the navigator to go to a new location (#46) +* Keyboard handling is now done in the viewer rather than navigator (#46) +* Additional navigator fixes (#46) +* Drawer events now fire properly (#94) +* Fixed an error in EventHandler.removeHandler() (#48) +* Better requestAnimationFrame detection on older Firefox (#103) +* More efficient navigator loading (#115) +* Simplified element opacity setting implementation (#123) + +0.9.127: + +* Fixed a problem with getString when the string property is a sub-property. (#64) +* Fixed: Tooltips for Navigation Controls not displaying (#63) +* Cleaned up some diagnostic code that was broken. +* Added fullpage class to viewer element when in fullpage mode (#61) +* Reverted to original New BSD license; cleaned up license declarations (#89) + +0.9.126: + +* DZI JSONp was broken; fixed. + +0.9.125: + +* Fully deprecated OpenSeadragon.createFromDZI, safely deprecated Viewer.openTileSource and + Viewer.openDZI to use Viewer.open internally. (#53 & #54). +* Full page bug fix for when viewer is child of document body (#43). +* Overlays for DZI bug fix (#45). +* DziTileSource: avoid changing relative paths (#56). +* Fix typo in preserveViewport handling (#77). +* Fix updateMulti timer leak after multiple Viewer.open() calls (#76). +* Minor documentation fixes. + +0.9.124: + +* Performance enhancements. + + +0.9.123: + +* Real fullscreen support. + + +0.9.122: + +* Performance enhancements. + + +0.9.121: + +* Touch pan now works on Android. +* Pinch zoom is better on all devices. diff --git a/js/openseadragon/openseadragon-bin-2.0.0/openseadragon.js b/js/openseadragon/openseadragon-bin-2.0.0/openseadragon.js index 5791b1f5d..5ec77f673 100644 --- a/js/openseadragon/openseadragon-bin-2.0.0/openseadragon.js +++ b/js/openseadragon/openseadragon-bin-2.0.0/openseadragon.js @@ -1,6 +1,6 @@ -//! openseadragon 2.1.0 -//! Built on 2015-12-01 -//! Git commit: v2.1.0-3-b2c17b5-dirty +//! OpenSeadragon 2.0.0 +//! Built on 2015-05-26 +//! Git commit: v2.0.0-0-472ab42 //! http://openseadragon.github.io //! License: http://openseadragon.github.io/license/ @@ -89,7 +89,7 @@ /** - * @version openseadragon 2.1.0 + * @version OpenSeadragon 2.0.0 * * @file *

      OpenSeadragon - Javascript Deep Zooming

      @@ -247,7 +247,7 @@ * @property {Number} [minZoomImageRatio=0.9] * The minimum percentage ( expressed as a number between 0 and 1 ) of * the viewport height or width at which the zoom out will be constrained. - * Setting it to 0, for example will allow you to zoom out infinity. + * Setting it to 0, for example will allow you to zoom out infinitly. * * @property {Number} [maxZoomPixelRatio=1.1] * The maximum ratio to allow a zoom-in to affect the highest level pixel @@ -258,14 +258,6 @@ * @property {Boolean} [autoResize=true] * Set to false to prevent polling for viewer size changes. Useful for providing custom resize behavior. * - * @property {Boolean} [preserveImageSizeOnResize=false] - * Set to true to have the image size preserved when the viewer is resized. This requires autoResize=true (default). - * - * @property {Number} [minScrollDeltaTime=50] - * Number of milliseconds between canvas-scroll events. This value helps normalize the rate of canvas-scroll - * events between different devices, causing the faster devices to slow down enough to make the zoom control - * more manageable. - * * @property {Number} [pixelsPerWheelLine=40] * For pixel-resolution scrolling devices, the number of pixels equal to one scroll line. * @@ -367,7 +359,7 @@ * @property {Boolean} [showNavigator=false] * Set to true to make the navigator minimap appear. * - * @property {String} [navigatorId=navigator-GENERATED DATE] + * @property {Boolean} [navigatorId=navigator-GENERATED DATE] * The ID of a div to hold the navigator minimap. * If an ID is specified, the navigatorPosition, navigatorSizeRatio, navigatorMaintainSizeRatio, and navigatorTop|Left|Height|Width options will be ignored. * If an ID is not specified, a div element will be generated and placed on top of the main image. @@ -570,10 +562,6 @@ * If collectionMode is true, specifies how many rows the grid should have. Use 1 to make a line. * If collectionLayout is 'vertical', specifies how many columns instead. * - * @property {Number} [collectionColumns=0] - * If collectionMode is true, specifies how many columns the grid should have. Use 1 to make a line. - * If collectionLayout is 'vertical', specifies how many rows instead. Ignored if collectionRows is not set to a falsy value. - * * @property {String} [collectionLayout='horizontal'] * If collectionMode is true, specifies whether to arrange vertically or horizontally. * @@ -698,12 +686,6 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){ }; -if (typeof define === 'function' && define.amd) { - define(function () { - return (window.OpenSeadragon); - }); -} - (function( $ ){ @@ -719,9 +701,9 @@ if (typeof define === 'function' && define.amd) { * @since 1.0.0 */ $.version = { - versionStr: '2.1.0', + versionStr: '2.0.0', major: parseInt('2', 10), - minor: parseInt('1', 10), + minor: parseInt('0', 10), revision: parseInt('0', 10) }; @@ -816,12 +798,10 @@ if (typeof define === 'function' && define.amd) { // Own properties are enumerated firstly, so to speed up, // if last one is own, then all properties are own. - var lastKey; - for (var key in obj ) { - lastKey = key; - } + var key; + for ( key in obj ) {} - return lastKey === undefined || hasOwn.call( obj, lastKey ); + return key === undefined || hasOwn.call( obj, key ); }; @@ -850,23 +830,6 @@ if (typeof define === 'function' && define.amd) { canvasElement.getContext( '2d' ) ); }()); - /** - * Test whether the submitted canvas is tainted or not. - * @argument {Canvas} canvas The canvas to test. - * @returns {Boolean} True if the canvas is tainted. - */ - $.isCanvasTainted = function(canvas) { - var isTainted = false; - try { - // We test if the canvas is tainted by retrieving data from it. - // An exception will be raised if the canvas is tainted. - var data = canvas.getContext('2d').getImageData(0, 0, 1, 1); - } catch (e) { - isTainted = true; - } - return isTainted; - }; - /** * A ratio comparing the device screen's pixel density to the canvas's backing store pixel density. Defaults to 1 if canvas isn't supported by the browser. * @member {Number} pixelDensityRatio @@ -1030,8 +993,6 @@ if (typeof define === 'function' && define.amd) { maxZoomPixelRatio: 1.1, //-> higher allows 'over zoom' into pixels pixelsPerWheelLine: 40, autoResize: true, - preserveImageSizeOnResize: false, // requires autoResize=true - minScrollDeltaTime: 50, //DEFAULT CONTROL SETTINGS showSequenceControl: true, //SEQUENCE @@ -1080,7 +1041,6 @@ if (typeof define === 'function' && define.amd) { //COLLECTION VISUALIZATION SETTINGS collectionRows: 3, //or columns depending on layout - collectionColumns: 0, //columns in horizontal layout, rows in vertical layout collectionLayout: 'horizontal', //vertical collectionMode: false, collectionTileSize: 800, @@ -2082,40 +2042,8 @@ if (typeof define === 'function' && define.amd) { request.onreadystatechange = function(){}; - if (window.XDomainRequest) { // IE9 or IE8 might as well try to use XDomainRequest - var xdr = new XDomainRequest(); - if (xdr) { - xdr.onload = function (e) { - if ( $.isFunction( onSuccess ) ) { - onSuccess({ // Faking an xhr object - responseText: xdr.responseText, - status: 200, // XDomainRequest doesn't support status codes, so we just fake one! :/ - statusText: 'OK' - }); - } - }; - xdr.onerror = function (e) { - if ( $.isFunction ( onError ) ) { - onError({ // Faking an xhr object - responseText: xdr.responseText, - status: 444, // 444 No Response - statusText: 'An error happened. Due to an XDomainRequest deficiency we can not extract any information about this error. Upgrade your browser.' - }); - } - }; - try { - xdr.open('GET', url); - xdr.send(); - } catch (e2) { - if ( $.isFunction( onError ) ) { - onError( request, e ); - } - } - } - } else { - if ( $.isFunction( onError ) ) { - onError( request, e ); - } + if ( $.isFunction( onError ) ) { + onError( request, e ); } } }, @@ -2245,24 +2173,6 @@ if (typeof define === 'function' && define.amd) { return $.parseXml( string ); }, - /** - * Parses a JSON string into a Javascript object. - * @function - * @param {String} string - * @returns {Object} - */ - parseJSON: function(string) { - if (window.JSON && window.JSON.parse) { - $.parseJSON = window.JSON.parse; - } else { - // Should only be used by IE8 in non standards mode - $.parseJSON = function(string) { - /*jshint evil:true*/ - return eval('(' + string + ')'); - }; - } - return $.parseJSON(string); - }, /** * Reports whether the image format is supported for tiling in this @@ -3156,7 +3066,7 @@ $.EventSource.prototype = /** @lends OpenSeadragon.EventSource.prototype */{ */ this.element = $.getElement( options.element ); /** - * The number of milliseconds within which a pointer down-up event combination + * The number of milliseconds within which a pointer down-up event combination * will be treated as a click gesture. * @member {Number} clickTimeThreshold * @memberof OpenSeadragon.MouseTracker# @@ -3267,7 +3177,7 @@ $.EventSource.prototype = /** @lends OpenSeadragon.EventSource.prototype */{ // Active pointers lists. Array of GesturePointList objects, one for each pointer device type. // GesturePointList objects are added each time a pointer is tracked by a new pointer device type (see getActivePointersListByType()). - // Active pointers are any pointer being tracked for this element which are in the hit-test area + // Active pointers are any pointer being tracked for this element which are in the hit-test area // of the element (for hover-capable devices) and/or have contact or a button press initiated in the element. activePointersLists: [], @@ -4055,7 +3965,7 @@ $.EventSource.prototype = /** @lends OpenSeadragon.EventSource.prototype */{ $.MouseTracker.mousePointerId = "legacy-mouse"; $.MouseTracker.maxTouchPoints = 10; } - + /////////////////////////////////////////////////////////////////////////////// // Classes and typedefs @@ -4101,7 +4011,7 @@ $.EventSource.prototype = /** @lends OpenSeadragon.EventSource.prototype */{ /** * @class GesturePointList * @classdesc Provides an abstraction for a set of active {@link OpenSeadragon.MouseTracker.GesturePoint|GesturePoint} objects for a given pointer device type. - * Active pointers are any pointer being tracked for this element which are in the hit-test area + * Active pointers are any pointer being tracked for this element which are in the hit-test area * of the element (for hover-capable devices) and/or have contact or a button press initiated in the element. * @memberof OpenSeadragon.MouseTracker * @param {String} type - The pointer device type: "mouse", "touch", "pen", etc. @@ -4221,7 +4131,7 @@ $.EventSource.prototype = /** @lends OpenSeadragon.EventSource.prototype */{ return null; } }; - + /////////////////////////////////////////////////////////////////////////////// // Utility functions @@ -4305,7 +4215,7 @@ $.EventSource.prototype = /** @lends OpenSeadragon.EventSource.prototype */{ false ); } - + clearTrackedPointers( tracker ); delegate.tracking = true; @@ -4717,7 +4627,7 @@ $.EventSource.prototype = /** @lends OpenSeadragon.EventSource.prototype */{ /** - * Handles 'wheel' events. + * Handles 'wheel' events. * The event may be simulated by the legacy mouse wheel event handler (onMouseWheel()). * * @private @@ -4966,7 +4876,7 @@ $.EventSource.prototype = /** @lends OpenSeadragon.EventSource.prototype */{ handleMouseMove( tracker, event ); } - + /** * This handler is attached to the window object (on the capture phase) to emulate mouse capture. * onMouseMove is still attached to the tracked element, so stop propagation to avoid processing twice. @@ -5213,10 +5123,16 @@ $.EventSource.prototype = /** @lends OpenSeadragon.EventSource.prototype */{ function onTouchCancel( tracker, event ) { var i, touchCount = event.changedTouches.length, - gPoints = [], - pointsList = tracker.getActivePointersListByType( 'touch' ); + gPoints = []; - abortTouchContacts( tracker, event, pointsList ); + for ( i = 0; i < touchCount; i++ ) { + gPoints.push( { + id: event.changedTouches[ i ].identifier, + type: 'touch' + } ); + } + + updatePointersCancel( tracker, event, gPoints ); } @@ -5437,7 +5353,7 @@ $.EventSource.prototype = /** @lends OpenSeadragon.EventSource.prototype */{ */ function startTrackingPointer( pointsList, gPoint ) { - // If isPrimary is not known for the pointer then set it according to our rules: + // If isPrimary is not known for the pointer then set it according to our rules: // true if the first pointer in the gesture, otherwise false if ( !gPoint.hasOwnProperty( 'isPrimary' ) ) { if ( pointsList.getLength() === 0 ) { @@ -5634,7 +5550,7 @@ $.EventSource.prototype = /** @lends OpenSeadragon.EventSource.prototype */{ * Gesture points associated with the event. * @param {Number} buttonChanged * The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. - * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model, + * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model, * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events. * * @returns {Boolean} True if pointers should be captured to the tracked element, otherwise false. @@ -5796,7 +5712,7 @@ $.EventSource.prototype = /** @lends OpenSeadragon.EventSource.prototype */{ * Gesture points associated with the event. * @param {Number} buttonChanged * The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. - * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model, + * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model, * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events. * * @returns {Boolean} True if pointer capture should be released from the tracked element, otherwise false. @@ -6909,8 +6825,6 @@ $.Viewer = function( options ) { this._loadQueue = []; this.currentOverlays = []; - this._lastScrollTime = $.now(); // variable used to help normalize the scroll event speed of different devices - //Inherit some behaviors and properties $.EventSource.call( this ); @@ -7313,14 +7227,6 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, options.success = function(event) { successes++; - // TODO: now that options has other things besides tileSource, the overlays - // should probably be at the options level, not the tileSource level. - if (options.tileSource.overlays) { - for (var i = 0; i < options.tileSource.overlays.length; i++) { - _this.addOverlay(options.tileSource.overlays[i]); - } - } - if (originalSuccess) { originalSuccess(event); } @@ -7344,6 +7250,14 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, }; _this.addTiledImage(options); + + // TODO: now that options has other things besides tileSource, the overlays + // should probably be at the options level, not the tileSource level. + if (options.tileSource.overlays) { + for (var i = 0; i < options.tileSource.overlays.length; i++) { + _this.addOverlay(options.tileSource.overlays[i]); + } + } }; // TileSources @@ -7901,10 +7815,6 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, * named 'getTileUrl', it is treated as a custom TileSource. * @param {Number} [options.index] The index of the item. Added on top of * all other items if not specified. - * @param {Boolean} [options.replace=false] If true, the item at options.index will be - * removed and the new item is added in its place. options.tileSource will be - * interpreted and fetched if necessary before the old item is removed to avoid leaving - * a gap in the world. * @param {Number} [options.x=0] The X position for the image in viewport coordinates. * @param {Number} [options.y=0] The Y position for the image in viewport coordinates. * @param {Number} [options.width=1] The width for the image in viewport coordinates. @@ -7928,15 +7838,9 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, addTiledImage: function( options ) { $.console.assert(options, "[Viewer.addTiledImage] options is required"); $.console.assert(options.tileSource, "[Viewer.addTiledImage] options.tileSource is required"); - $.console.assert(!options.replace || (options.index > -1 && options.index < this.world.getItemCount()), - "[Viewer.addTiledImage] if options.replace is used, options.index must be a valid index in Viewer.world"); var _this = this; - if (options.replace) { - options.replaceItem = _this.world.getItemAt(options.index); - } - this._hideMessage(); if (options.placeholderFillStyle === undefined) { @@ -7951,17 +7855,13 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, }; function raiseAddItemFailed( event ) { - for (var i = 0; i < _this._loadQueue.length; i++) { + for (var i = 0; i < _this._loadQueue; i++) { if (_this._loadQueue[i] === myQueueItem) { _this._loadQueue.splice(i, 1); break; } } - if (_this._loadQueue.length === 0) { - refreshWorld(myQueueItem); - } - /** * Raised when an error occurs while adding a item. * @event add-item-failed @@ -7980,34 +7880,18 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, } } - function refreshWorld(theItem) { - if (_this.collectionMode) { - _this.world.arrange({ - immediately: theItem.options.collectionImmediately, - rows: _this.collectionRows, - columns: _this.collectionColumns, - layout: _this.collectionLayout, - tileSize: _this.collectionTileSize, - tileMargin: _this.collectionTileMargin - }); - _this.world.setAutoRefigureSizes(true); - } - } + this._loadQueue.push(myQueueItem); + + getTileSourceImplementation( this, options.tileSource, function( tileSource ) { - if ($.isArray(options.tileSource)) { - setTimeout(function() { + if ( tileSource instanceof Array ) { raiseAddItemFailed({ message: "[Viewer.addTiledImage] Sequences can not be added; add them one at a time instead.", - source: options.tileSource, + source: tileSource, options: options }); - }); - return; - } - - this._loadQueue.push(myQueueItem); - - getTileSourceImplementation( this, options.tileSource, function( tileSource ) { + return; + } myQueueItem.tileSource = tileSource; @@ -8021,14 +7905,6 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, _this._loadQueue.splice(0, 1); - if (queueItem.options.replace) { - var newIndex = _this.world.getIndexOfItem(queueItem.options.replaceItem); - if (newIndex != -1) { - queueItem.options.index = newIndex; - } - _this.world.removeItem(queueItem.options.replaceItem); - } - tiledImage = new $.TiledImage({ viewer: _this, source: queueItem.tileSource, @@ -8056,16 +7932,18 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, debugMode: _this.debugMode }); - if (_this.collectionMode) { - _this.world.setAutoRefigureSizes(false); - } _this.world.addItem( tiledImage, { index: queueItem.options.index }); - if (_this._loadQueue.length === 0) { - //this restores the autoRefigureSizes flag to true. - refreshWorld(queueItem); + if (_this.collectionMode) { + _this.world.arrange({ + immediately: queueItem.options.collectionImmediately, + rows: _this.collectionRows, + layout: _this.collectionLayout, + tileSize: _this.collectionTileSize, + tileMargin: _this.collectionTileMargin + }); } if (_this.world.getItemCount() === 1 && !_this.preserveViewport) { @@ -8454,7 +8332,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, * is closed which include when changing page. * @method * @param {Element|String|Object} element - A reference to an element or an id for - * the element which will be overlayed. Or an Object specifying the configuration for the overlay + * the element which will overlayed. Or an Object specifying the configuration for the overlay * @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or * rectangle which will be overlayed. * @param {OpenSeadragon.OverlayPlacement} placement - The position of the @@ -8514,8 +8392,6 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, * Updates the overlay represented by the reference to the element or * element id moving it to the new location, relative to the new placement. * @method - * @param {Element|String} element - A reference to an element or an id for - * the element which is overlayed. * @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or * rectangle which will be overlayed. * @param {OpenSeadragon.OverlayPlacement} placement - The position of the @@ -8707,13 +8583,6 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, for ( i = 0; i < length; i++ ) { this.currentOverlays[ i ].drawHTML( this.overlaysContainer, this.viewport ); } - }, - - /** - * Cancel the "in flight" images. - */ - _cancelPendingImages: function() { - this._loadQueue = []; } }); @@ -8746,23 +8615,8 @@ function getTileSourceImplementation( viewer, tileSource, successCallback, if ( tileSource.match( /\s*<.*/ ) ) { tileSource = $.parseXml( tileSource ); } else if ( tileSource.match( /\s*[\{\[].*/ ) ) { - tileSource = $.parseJSON(tileSource); - } - } - - function waitUntilReady(tileSource, originalTileSource) { - if (tileSource.ready) { - successCallback(tileSource); - } else { - tileSource.addHandler('ready', function () { - successCallback(tileSource); - }); - tileSource.addHandler('open-failed', function (event) { - failCallback({ - message: event.message, - source: originalTileSource - }); - }); + /*jshint evil:true*/ + tileSource = eval( '(' + tileSource + ')' ); } } @@ -8771,9 +8625,7 @@ function getTileSourceImplementation( viewer, tileSource, successCallback, //If its still a string it means it must be a url at this point tileSource = new $.TileSource({ url: tileSource, - crossOriginPolicy: viewer.crossOriginPolicy, ajaxWithCredentials: viewer.ajaxWithCredentials, - useCanvas: viewer.useCanvas, success: function( event ) { successCallback( event.tileSource ); } @@ -8782,16 +8634,10 @@ function getTileSourceImplementation( viewer, tileSource, successCallback, failCallback( event ); } ); - } else if ($.isPlainObject(tileSource) || tileSource.nodeType) { - if (!tileSource.crossOriginPolicy && viewer.crossOriginPolicy) { - tileSource.crossOriginPolicy = viewer.crossOriginPolicy; - } + } else if ( $.isPlainObject( tileSource ) || tileSource.nodeType ) { if (tileSource.ajaxWithCredentials === undefined) { tileSource.ajaxWithCredentials = viewer.ajaxWithCredentials; } - if (tileSource.useCanvas === undefined) { - tileSource.useCanvas = viewer.useCanvas; - } if ( $.isFunction( tileSource.getTileUrl ) ) { //Custom tile source @@ -8809,13 +8655,14 @@ function getTileSourceImplementation( viewer, tileSource, successCallback, return; } var options = $TileSource.prototype.configure.apply( _this, [ tileSource ] ); - waitUntilReady(new $TileSource(options), tileSource); + var readySource = new $TileSource( options ); + successCallback( readySource ); } } else { //can assume it's already a tile source implementation - waitUntilReady(tileSource, tileSource); + successCallback( tileSource ); } - }); + }, 1 ); } function getOverlayObject( viewer, overlay ) { @@ -9026,7 +8873,6 @@ function onCanvasKeyDown( event ) { function onCanvasKeyPress( event ) { if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { switch( event.keyCode ){ - case 43://=|+ case 61://=|+ this.viewport.zoomBy(1.1); this.viewport.applyConstraints(); @@ -9471,57 +9317,44 @@ function onCanvasPinch( event ) { function onCanvasScroll( event ) { var gestureSettings, - factor, - thisScrollTime, - deltaScrollTime; - - /* Certain scroll devices fire the scroll event way too fast so we are injecting a simple adjustment to keep things - * partially normalized. If we have already fired an event within the last 'minScrollDelta' milliseconds we skip - * this one and wait for the next event. */ - thisScrollTime = $.now(); - deltaScrollTime = thisScrollTime - this._lastScrollTime; - if (deltaScrollTime > this.minScrollDeltaTime) { - this._lastScrollTime = thisScrollTime; - - if ( !event.preventDefaultAction && this.viewport ) { - gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); - if ( gestureSettings.scrollToZoom ) { - factor = Math.pow( this.zoomPerScroll, event.scroll ); - this.viewport.zoomBy( - factor, - this.viewport.pointFromPixel( event.position, true ) - ); - this.viewport.applyConstraints(); - } - } - /** - * Raised when a scroll event occurs on the {@link OpenSeadragon.Viewer#canvas} element (mouse wheel). - * - * @event canvas-scroll - * @memberof OpenSeadragon.Viewer - * @type {object} - * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. - * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. - * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. - * @property {Number} scroll - The scroll delta for the event. - * @property {Boolean} shift - True if the shift key was pressed during this event. - * @property {Object} originalEvent - The original DOM event. - * @property {?Object} userData - Arbitrary subscriber-defined object. - */ - this.raiseEvent( 'canvas-scroll', { - tracker: event.eventSource, - position: event.position, - scroll: event.scroll, - shift: event.shift, - originalEvent: event.originalEvent - }); - if (gestureSettings && gestureSettings.scrollToZoom) { - //cancels event - return false; + factor; + + if ( !event.preventDefaultAction && this.viewport ) { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); + if ( gestureSettings.scrollToZoom ) { + factor = Math.pow( this.zoomPerScroll, event.scroll ); + this.viewport.zoomBy( + factor, + this.viewport.pointFromPixel( event.position, true ) + ); + this.viewport.applyConstraints(); } } - else { - return false; // We are swallowing this event + /** + * Raised when a scroll event occurs on the {@link OpenSeadragon.Viewer#canvas} element (mouse wheel). + * + * @event canvas-scroll + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} scroll - The scroll delta for the event. + * @property {Boolean} shift - True if the shift key was pressed during this event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-scroll', { + tracker: event.eventSource, + position: event.position, + scroll: event.scroll, + shift: event.shift, + originalEvent: event.originalEvent + }); + + if (gestureSettings && gestureSettings.scrollToZoom) { + //cancels event + return false; } } @@ -9613,31 +9446,13 @@ function updateOnce( viewer ) { return; } - var containerSize; if ( viewer.autoResize ) { - containerSize = _getSafeElemSize( viewer.container ); + var containerSize = _getSafeElemSize( viewer.container ); if ( !containerSize.equals( THIS[ viewer.hash ].prevContainerSize ) ) { - if ( viewer.preserveImageSizeOnResize ) { - var prevContainerSize = THIS[ viewer.hash ].prevContainerSize; - var bounds = viewer.viewport.getBounds(true); - var deltaX = (containerSize.x - prevContainerSize.x); - var deltaY = (containerSize.y - prevContainerSize.y); - var viewportDiff = viewer.viewport.deltaPointsFromPixels(new OpenSeadragon.Point(deltaX, deltaY), true); - viewer.viewport.resize(new OpenSeadragon.Point(containerSize.x, containerSize.y), false); - - // Keep the center of the image in the center and just adjust the amount of image shown - bounds.width += viewportDiff.x; - bounds.height += viewportDiff.y; - bounds.x -= (viewportDiff.x / 2); - bounds.y -= (viewportDiff.y / 2); - viewer.viewport.fitBoundsWithConstraints(bounds, true); - } - else { - // maintain image position - var oldBounds = viewer.viewport.getBounds(); - var oldCenter = viewer.viewport.getCenter(); - resizeViewportAndRecenter(viewer, containerSize, oldBounds, oldCenter); - } + // maintain image position + var oldBounds = viewer.viewport.getBounds(); + var oldCenter = viewer.viewport.getCenter(); + resizeViewportAndRecenter(viewer, containerSize, oldBounds, oldCenter); THIS[ viewer.hash ].prevContainerSize = containerSize; THIS[ viewer.hash ].forceRedraw = true; } @@ -9734,15 +9549,19 @@ function resizeViewportAndRecenter( viewer, containerSize, oldBounds, oldCenter viewport.resize( containerSize, true ); - var newBounds = new $.Rect( - oldCenter.x - ( oldBounds.width / 2.0 ), - oldCenter.y - ( oldBounds.height / 2.0 ), - oldBounds.width, - oldBounds.height - ); + // We try to remove blanks as much as possible + var worldBounds = viewer.world.getHomeBounds(); + var newWidth = oldBounds.width <= worldBounds.width ? oldBounds.width : worldBounds.width; + var newHeight = oldBounds.height <= worldBounds.height ? + oldBounds.height : worldBounds.height; - // let the viewport decide if the bounds are too big or too small - viewport.fitBoundsWithConstraints( newBounds, true ); + var newBounds = new $.Rect( + oldCenter.x - ( newWidth / 2.0 ), + oldCenter.y - ( newHeight / 2.0 ), + newWidth, + newHeight + ); + viewport.fitBounds( newBounds, true ); } function drawWorld( viewer ) { @@ -10030,9 +9849,7 @@ $.Navigator = function( options ){ immediateRender: true, blendTime: 0, animationTime: 0, - autoResize: options.autoResize, - // prevent resizing the navigator from adding unwanted space around the image - minZoomImageRatio: 1.0 + autoResize: options.autoResize }); options.minPixelRatio = this.minPixelRatio = viewer.minPixelRatio; @@ -10788,11 +10605,6 @@ $.Point.prototype = /** @lends OpenSeadragon.Point.prototype */{ * The size of the tiles to assumed to make up each pyramid layer in pixels. * Tile size determines the point at which the image pyramid must be * divided into a matrix of smaller images. - * Use options.tileWidth and options.tileHeight to support non-square tiles. - * @param {Number} [options.tileWidth] - * The width of the tiles to assumed to make up each pyramid layer in pixels. - * @param {Number} [options.tileHeight] - * The height of the tiles to assumed to make up each pyramid layer in pixels. * @param {Number} [options.tileOverlap] * The number of pixels each tile is expected to overlap touching tiles. * @param {Number} [options.minLevel] @@ -10857,6 +10669,13 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve * @member {OpenSeadragon.Point} dimensions * @memberof OpenSeadragon.TileSource# */ + /** + * The size of the image tiles used to compose the image. + * Please note that tileSize may be deprecated in a future release. + * Instead the getTileSize(level) function should be used. + * @member {Number} tileSize + * @memberof OpenSeadragon.TileSource# + */ /** * The overlap in pixels each tile shares with its adjacent neighbors. * @member {Number} tileOverlap @@ -10887,8 +10706,7 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve //async mechanism set some safe defaults first this.aspectRatio = 1; this.dimensions = new $.Point( 10, 10 ); - this._tileWidth = 0; - this._tileHeight = 0; + this.tileSize = 0; this.tileOverlap = 0; this.minLevel = 0; this.maxLevel = 0; @@ -10905,29 +10723,7 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve this.aspectRatio = ( options.width && options.height ) ? ( options.width / options.height ) : 1; this.dimensions = new $.Point( options.width, options.height ); - - if ( this.tileSize ){ - this._tileWidth = this._tileHeight = this.tileSize; - delete this.tileSize; - } else { - if( this.tileWidth ){ - // We were passed tileWidth in options, but we want to rename it - // with a leading underscore to make clear that it is not safe to directly modify it - this._tileWidth = this.tileWidth; - delete this.tileWidth; - } else { - this._tileWidth = 0; - } - - if( this.tileHeight ){ - // See note above about renaming this.tileWidth - this._tileHeight = this.tileHeight; - delete this.tileHeight; - } else { - this._tileHeight = 0; - } - } - + this.tileSize = options.tileSize ? options.tileSize : 0; this.tileOverlap = options.tileOverlap ? options.tileOverlap : 0; this.minLevel = options.minLevel ? options.minLevel : 0; this.maxLevel = ( undefined !== options.maxLevel && null !== options.maxLevel ) ? @@ -10948,42 +10744,16 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{ - getTileSize: function( level ) { - $.console.error( - "[TileSource.getTileSize] is deprecated." + - "Use TileSource.getTileWidth() and TileSource.getTileHeight() instead" - ); - return this._tileWidth; - }, - /** - * Return the tileWidth for a given level. - * Subclasses should override this if tileWidth can be different at different levels + * Return the tileSize for a given level. + * Subclasses should override this if tileSizes can be different at different levels * such as in IIIFTileSource. Code should use this function rather than reading - * from ._tileWidth directly. + * from .tileSize directly. tileSize may be deprecated in a future release. * @function * @param {Number} level */ - getTileWidth: function( level ) { - if (!this._tileWidth) { - return this.getTileSize(level); - } - return this._tileWidth; - }, - - /** - * Return the tileHeight for a given level. - * Subclasses should override this if tileHeight can be different at different levels - * such as in IIIFTileSource. Code should use this function rather than reading - * from ._tileHeight directly. - * @function - * @param {Number} level - */ - getTileHeight: function( level ) { - if (!this._tileHeight) { - return this.getTileSize(level); - } - return this._tileHeight; + getTileSize: function( level ) { + return this.tileSize; }, /** @@ -11012,8 +10782,8 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{ */ getNumTiles: function( level ) { var scale = this.getLevelScale( level ), - x = Math.ceil( scale * this.dimensions.x / this.getTileWidth(level) ), - y = Math.ceil( scale * this.dimensions.y / this.getTileHeight(level) ); + x = Math.ceil( scale * this.dimensions.x / this.getTileSize(level) ), + y = Math.ceil( scale * this.dimensions.y / this.getTileSize(level) ); return new $.Point( x, y ); }, @@ -11039,15 +10809,10 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{ var i, tilesPerSide, tiles; - for( i = this.minLevel; i < this.maxLevel; i++ ){ tiles = this.getNumTiles( i ); - tilesPerSide = new $.Point( - Math.floor( rect.x / this.getTileWidth(i) ), - Math.floor( rect.y / this.getTileHeight(i) ) - ); - - if( tiles.x + 1 >= tilesPerSide.x && tiles.y + 1 >= tilesPerSide.y ){ + tilesPerSide = Math.floor( Math.max( rect.x, rect.y ) / this.getTileSize(i) ); + if( Math.max( tiles.x, tiles.y ) + 1 >= tilesPerSide ){ break; } } @@ -11060,9 +10825,9 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{ * @param {OpenSeadragon.Point} point */ getTileAtPoint: function( level, point ) { - var pixel = point.times( this.dimensions.x ).times( this.getLevelScale(level) ), - tx = Math.floor( pixel.x / this.getTileWidth(level) ), - ty = Math.floor( pixel.y / this.getTileHeight(level) ); + var pixel = point.times( this.dimensions.x ).times( this.getLevelScale(level ) ), + tx = Math.floor( pixel.x / this.getTileSize(level) ), + ty = Math.floor( pixel.y / this.getTileSize(level) ); return new $.Point( tx, ty ); }, @@ -11075,12 +10840,11 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{ */ getTileBounds: function( level, x, y ) { var dimensionsScaled = this.dimensions.times( this.getLevelScale( level ) ), - tileWidth = this.getTileWidth(level), - tileHeight = this.getTileHeight(level), - px = ( x === 0 ) ? 0 : tileWidth * x - this.tileOverlap, - py = ( y === 0 ) ? 0 : tileHeight * y - this.tileOverlap, - sx = tileWidth + ( x === 0 ? 1 : 2 ) * this.tileOverlap, - sy = tileHeight + ( y === 0 ? 1 : 2 ) * this.tileOverlap, + tileSize = this.getTileSize(level), + px = ( x === 0 ) ? 0 : tileSize * x - this.tileOverlap, + py = ( y === 0 ) ? 0 : tileSize * y - this.tileOverlap, + sx = tileSize + ( x === 0 ? 1 : 2 ) * this.tileOverlap, + sy = tileSize + ( y === 0 ? 1 : 2 ) * this.tileOverlap, scale = 1.0 / dimensionsScaled.x; sx = Math.min( sx, dimensionsScaled.x - px ); @@ -11328,7 +11092,8 @@ function processResponse( xhr ){ data = xhr.responseText; } }else if( responseText.match(/\s*[\{\[].*/) ){ - data = $.parseJSON(responseText); + /*jshint evil:true*/ + data = eval( '('+responseText+')' ); }else{ data = responseText; } @@ -11790,19 +11555,14 @@ $.IIIFTileSource = function( options ){ options.tileSizePerScaleFactor = {}; // N.B. 2.0 renamed scale_factors to scaleFactors - if ( this.tile_width && this.tile_height ) { - options.tileWidth = this.tile_width; - options.tileHeight = this.tile_height; - } else if ( this.tile_width ) { + if ( this.tile_width ) { options.tileSize = this.tile_width; } else if ( this.tile_height ) { options.tileSize = this.tile_height; } else if ( this.tiles ) { // Version 2.0 forwards if ( this.tiles.length == 1 ) { - options.tileWidth = this.tiles[0].width; - // Use height if provided, otherwise assume square tiles and use width. - options.tileHeight = this.tiles[0].height || this.tiles[0].width; + options.tileSize = this.tiles[0].width; this.scale_factors = this.tiles[0].scaleFactors; } else { // Multiple tile sizes at different levels @@ -11811,15 +11571,13 @@ $.IIIFTileSource = function( options ){ for (var sf = 0; sf < this.tiles[t].scaleFactors.length; sf++) { var scaleFactor = this.tiles[t].scaleFactors[sf]; this.scale_factors.push(scaleFactor); - options.tileSizePerScaleFactor[scaleFactor] = { - width: this.tiles[t].width, - height: this.tiles[t].height || this.tiles[t].width - }; + options.tileSizePerScaleFactor[scaleFactor] = this.tiles[t].width; } } } } else { // use the largest of tileOptions that is smaller than the short dimension + var shortDim = Math.min( this.height, this.width ), tileOptions = [256,512,1024], smallerTiles = []; @@ -11836,6 +11594,8 @@ $.IIIFTileSource = function( options ){ // If we're smaller than 256, just use the short side. options.tileSize = shortDim; } + this.tile_width = options.tileSize; // So that 'full' gets used for + this.tile_height = options.tileSize; // the region below } if ( !options.maxLevel ) { @@ -11857,7 +11617,6 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea * @param {Object|Array} data * @param {String} optional - url */ - supports: function( data, url ) { // Version 2.0 and forwards if (data.protocol && data.protocol == 'http://iiif.io/api/image') { @@ -11922,34 +11681,20 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea }, /** - * Return the tileWidth for the given level. + * Return the tileSize for the given level. * @function * @param {Number} level - */ - getTileWidth: function( level ) { - var scaleFactor = Math.pow(2, this.maxLevel - level); - - if (this.tileSizePerScaleFactor && this.tileSizePerScaleFactor[scaleFactor]) { - return this.tileSizePerScaleFactor[scaleFactor].width; - } - return this._tileWidth; - }, + */ - /** - * Return the tileHeight for the given level. - * @function - * @param {Number} level - */ - getTileHeight: function( level ) { + getTileSize: function( level ){ var scaleFactor = Math.pow(2, this.maxLevel - level); - + // cache it in case any external code is going to read it directly if (this.tileSizePerScaleFactor && this.tileSizePerScaleFactor[scaleFactor]) { - return this.tileSizePerScaleFactor[scaleFactor].height; + this.tileSize = this.tileSizePerScaleFactor[scaleFactor]; } - return this._tileHeight; + return this.tileSize; }, - /** * Responsible for retreiving the url which will return an image for the * region specified by the given x, y, and level components. @@ -11971,8 +11716,7 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea levelHeight = Math.ceil( this.height * scale ), //## iiif region - tileWidth, - tileHeight, + tileSize, iiifTileSizeWidth, iiifTileSizeHeight, iiifRegion, @@ -11984,10 +11728,9 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea iiifQuality, uri; - tileWidth = this.getTileWidth(level); - tileHeight = this.getTileHeight(level); - iiifTileSizeWidth = Math.ceil( tileWidth / scale ); - iiifTileSizeHeight = Math.ceil( tileHeight / scale ); + tileSize = this.getTileSize(level); + iiifTileSizeWidth = Math.ceil( tileSize / scale ); + iiifTileSizeHeight = iiifTileSizeWidth; if ( this['@context'].indexOf('/1.0/context.json') > -1 || this['@context'].indexOf('/1.1/context.json') > -1 || @@ -11997,7 +11740,7 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea iiifQuality = "default.jpg"; } - if ( levelWidth < tileWidth && levelHeight < tileHeight ){ + if ( levelWidth < tileSize && levelHeight < tileSize ){ iiifSize = levelWidth + ","; iiifRegion = 'full'; } else { @@ -12657,295 +12400,6 @@ function configureFromObject( tileSource, configuration ){ }( OpenSeadragon )); -/* - * OpenSeadragon - ImageTileSource - * - * Copyright (C) 2009 CodePlex Foundation - * Copyright (C) 2010-2013 OpenSeadragon contributors - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of CodePlex Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -(function ($) { - - /** - * @class ImageTileSource - * @classdesc The ImageTileSource allows a simple image to be loaded - * into an OpenSeadragon Viewer. - * There are 2 ways to open an ImageTileSource: - * 1. viewer.open({type: 'image', url: fooUrl}); - * 2. viewer.open(new OpenSeadragon.ImageTileSource({url: fooUrl})); - * - * With the first syntax, the crossOriginPolicy, ajaxWithCredentials and - * useCanvas options are inherited from the viewer if they are not - * specified directly in the options object. - * - * @memberof OpenSeadragon - * @extends OpenSeadragon.TileSource - * @param {Object} options Options object. - * @param {String} options.url URL of the image - * @param {Boolean} [options.buildPyramid=true] If set to true (default), a - * pyramid will be built internally to provide a better downsampling. - * @param {String|Boolean} [options.crossOriginPolicy=false] Valid values are - * 'Anonymous', 'use-credentials', and false. If false, image requests will - * not use CORS preventing internal pyramid building for images from other - * domains. - * @param {String|Boolean} [options.ajaxWithCredentials=false] Whether to set - * the withCredentials XHR flag for AJAX requests (when loading tile sources). - * @param {Boolean} [options.useCanvas=true] Set to false to prevent any use - * of the canvas API. - */ - $.ImageTileSource = function (options) { - - options = $.extend({ - buildPyramid: true, - crossOriginPolicy: false, - ajaxWithCredentials: false, - useCanvas: true - }, options); - $.TileSource.apply(this, [options]); - - }; - - $.extend($.ImageTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.ImageTileSource.prototype */{ - /** - * Determine if the data and/or url imply the image service is supported by - * this tile source. - * @function - * @param {Object|Array} data - * @param {String} optional - url - */ - supports: function (data, url) { - return data.type && data.type === "image"; - }, - /** - * - * @function - * @param {Object} options - the options - * @param {String} dataUrl - the url the image was retreived from, if any. - * @return {Object} options - A dictionary of keyword arguments sufficient - * to configure this tile sources constructor. - */ - configure: function (options, dataUrl) { - return options; - }, - /** - * Responsible for retrieving, and caching the - * image metadata pertinent to this TileSources implementation. - * @function - * @param {String} url - * @throws {Error} - */ - getImageInfo: function (url) { - var image = this._image = new Image(); - var _this = this; - - if (this.crossOriginPolicy) { - image.crossOrigin = this.crossOriginPolicy; - } - if (this.ajaxWithCredentials) { - image.useCredentials = this.ajaxWithCredentials; - } - - $.addEvent(image, 'load', function () { - _this.width = image.naturalWidth; - _this.height = image.naturalHeight; - _this.aspectRatio = _this.width / _this.height; - _this.dimensions = new $.Point(_this.width, _this.height); - _this._tileWidth = _this.width; - _this._tileHeight = _this.height; - _this.tileOverlap = 0; - _this.minLevel = 0; - _this.levels = _this._buildLevels(); - _this.maxLevel = _this.levels.length - 1; - - _this.ready = true; - /** - * Raised when a TileSource is opened and initialized. - * - * @event ready - * @memberof OpenSeadragon.TileSource - * @type {object} - * @property {OpenSeadragon.TileSource} eventSource - A reference - * to the TileSource which raised the event. - * @property {Object} tileSource - * @property {?Object} userData - Arbitrary subscriber-defined object. - */ - _this.raiseEvent('ready', {tileSource: _this}); - }); - - $.addEvent(image, 'error', function () { - /*** - * Raised when an error occurs loading a TileSource. - * - * @event open-failed - * @memberof OpenSeadragon.TileSource - * @type {object} - * @property {OpenSeadragon.TileSource} eventSource - A reference - * to the TileSource which raised the event. - * @property {String} message - * @property {String} source - * @property {?Object} userData - Arbitrary subscriber-defined object. - */ - _this.raiseEvent('open-failed', { - message: "Error loading image at " + url, - source: url - }); - }); - - image.src = url; - }, - /** - * @function - * @param {Number} level - */ - getLevelScale: function (level) { - var levelScale = NaN; - if (level >= this.minLevel && level <= this.maxLevel) { - levelScale = - this.levels[level].width / - this.levels[this.maxLevel].width; - } - return levelScale; - }, - /** - * @function - * @param {Number} level - */ - getNumTiles: function (level) { - var scale = this.getLevelScale(level); - if (scale) { - return new $.Point(1, 1); - } else { - return new $.Point(0, 0); - } - }, - /** - * @function - * @param {Number} level - * @param {OpenSeadragon.Point} point - */ - getTileAtPoint: function (level, point) { - return new $.Point(0, 0); - }, - /** - * Retrieves a tile url - * @function - * @param {Number} level Level of the tile - * @param {Number} x x coordinate of the tile - * @param {Number} y y coordinate of the tile - */ - getTileUrl: function (level, x, y) { - var url = null; - if (level >= this.minLevel && level <= this.maxLevel) { - url = this.levels[level].url; - } - return url; - }, - /** - * Retrieves a tile context 2D - * @function - * @param {Number} level Level of the tile - * @param {Number} x x coordinate of the tile - * @param {Number} y y coordinate of the tile - */ - getContext2D: function (level, x, y) { - var context = null; - if (level >= this.minLevel && level <= this.maxLevel) { - context = this.levels[level].context2D; - } - return context; - }, - - // private - // - // Builds the differents levels of the pyramid if possible - // (i.e. if canvas API enabled and no canvas tainting issue). - _buildLevels: function () { - var levels = [{ - url: this._image.src, - width: this._image.naturalWidth, - height: this._image.naturalHeight - }]; - - if (!this.buildPyramid || !$.supportsCanvas || !this.useCanvas) { - // We don't need the image anymore. Allows it to be GC. - delete this._image; - return levels; - } - - var currentWidth = this._image.naturalWidth; - var currentHeight = this._image.naturalHeight; - - var bigCanvas = document.createElement("canvas"); - var bigContext = bigCanvas.getContext("2d"); - - bigCanvas.width = currentWidth; - bigCanvas.height = currentHeight; - bigContext.drawImage(this._image, 0, 0, currentWidth, currentHeight); - // We cache the context of the highest level because the browser - // is a lot faster at downsampling something it already has - // downsampled before. - levels[0].context2D = bigContext; - // We don't need the image anymore. Allows it to be GC. - delete this._image; - - if ($.isCanvasTainted(bigCanvas)) { - // If the canvas is tainted, we can't compute the pyramid. - return levels; - } - - // We build smaller levels until either width or height becomes - // 1 pixel wide. - while (currentWidth >= 2 && currentHeight >= 2) { - currentWidth = Math.floor(currentWidth / 2); - currentHeight = Math.floor(currentHeight / 2); - var smallCanvas = document.createElement("canvas"); - var smallContext = smallCanvas.getContext("2d"); - smallCanvas.width = currentWidth; - smallCanvas.height = currentHeight; - smallContext.drawImage(bigCanvas, 0, 0, currentWidth, currentHeight); - - levels.splice(0, 0, { - context2D: smallContext, - width: currentWidth, - height: currentHeight - }); - - bigCanvas = smallCanvas; - bigContext = smallContext; - } - return levels; - } - }); - -}(OpenSeadragon)); - /* * OpenSeadragon - TileSourceCollection * @@ -13568,7 +13022,7 @@ $.ButtonGroup = function( options ) { */ this.element = options.element || $.makeNeutralElement( "div" ); - // TODO What if there IS an options.group specified? + // TODO What if there IS an options.group specified? if( !options.group ){ this.label = $.makeNeutralElement( "label" ); //TODO: support labels for ButtonGroups @@ -14898,7 +14352,6 @@ function ImageJob ( options ) { } ImageJob.prototype = { - errorMsg: null, start: function(){ var _this = this; @@ -14912,12 +14365,10 @@ ImageJob.prototype = { _this.finish( true ); }; this.image.onabort = this.image.onerror = function(){ - _this.errorMsg = "Image load aborted"; _this.finish( false ); }; this.jobId = window.setTimeout( function(){ - _this.errorMsg = "Image load exceeded timeout"; _this.finish( false ); }, this.timeout); @@ -15023,7 +14474,7 @@ function completeJob( loader, job, callback ) { loader.jobsInProgress++; } - callback( job.image, job.errorMsg ); + callback( job.image ); } }( OpenSeadragon )); @@ -15075,10 +14526,8 @@ function completeJob( loader, job, callback ) { * @param {Boolean} exists Is this tile a part of a sparse image? ( Also has * this tile failed to load? ) * @param {String} url The URL of this tile's image. - * @param {CanvasRenderingContext2D} context2D The context2D of this tile if it - * is provided directly by the tile source. */ -$.Tile = function(level, x, y, bounds, exists, url, context2D) { +$.Tile = function(level, x, y, bounds, exists, url) { /** * The zoom level this tile belongs to. * @member {Number} level @@ -15115,12 +14564,6 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D) { * @memberof OpenSeadragon.Tile# */ this.url = url; - /** - * The context2D of this tile if it is provided directly by the tile source. - * @member {CanvasRenderingContext2D} context2D - * @memberOf OpenSeadragon.Tile# - */ - this.context2D = context2D; /** * Is this tile loaded? * @member {Boolean} loaded @@ -15228,14 +14671,7 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{ * @param {Element} container */ drawHTML: function( container ) { - if (!this.cacheImageRecord) { - $.console.warn( - '[Tile.drawHTML] attempting to draw tile %s when it\'s not cached', - this.toString()); - return; - } - - if ( !this.loaded ) { + if ( !this.loaded || !this.image ) { $.console.warn( "Attempting to draw tile %s when it's not yet loaded.", this.toString() @@ -15248,7 +14684,8 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{ if ( !this.element ) { this.element = $.makeNeutralElement( "div" ); - this.imgElement = this.cacheImageRecord.getImage().cloneNode(); + this.imgElement = $.makeNeutralElement( "img" ); + this.imgElement.src = this.url; this.imgElement.style.msInterpolationMode = "nearest-neighbor"; this.imgElement.style.width = "100%"; this.imgElement.style.height = "100%"; @@ -15283,18 +14720,17 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{ var position = this.position, size = this.size, - rendered; + rendered, + canvas; - if (!this.context2D && !this.cacheImageRecord) { - $.console.warn( - '[Tile.drawCanvas] attempting to draw tile %s when it\'s not cached', - this.toString()); + if (!this.cacheImageRecord) { + $.console.warn('[Tile.drawCanvas] attempting to draw tile %s when it\'s not cached', this.toString()); return; } - rendered = this.context2D || this.cacheImageRecord.getRenderedContext(); + rendered = this.cacheImageRecord.getRenderedContext(); - if ( !this.loaded || !rendered ){ + if ( !this.loaded || !( this.image || rendered) ){ $.console.warn( "Attempting to draw tile %s when it's not yet loaded.", this.toString() @@ -15303,16 +14739,13 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{ return; } - context.save(); - context.globalAlpha = this.opacity; //if we are supposed to be rendering fully opaque rectangle, //ie its done fading or fading is turned off, and if we are drawing //an image with an alpha channel, then the only way //to avoid seeing the tile underneath is to clear the rectangle - if (context.globalAlpha === 1 && - (this.context2D || this.url.match('.png'))) { + if( context.globalAlpha == 1 && this.url.match('.png') ){ //clearing only the inside of the rectangle occupied //by the png prevents edge flikering context.clearRect( @@ -15324,8 +14757,19 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{ } - // This gives the application a chance to make image manipulation - // changes as we are rendering the image + if(!rendered){ + canvas = document.createElement( 'canvas' ); + canvas.width = this.image.width; + canvas.height = this.image.height; + rendered = canvas.getContext('2d'); + rendered.drawImage( this.image, 0, 0 ); + this.cacheImageRecord.setRenderedContext(rendered); + //since we are caching the prerendered image on a canvas + //allow the image to not be held in memory + this.image = null; + } + + // This gives the application a chance to make image manipulation changes as we are rendering the image drawingHandler({context: context, tile: this, rendered: rendered}); context.drawImage( @@ -15339,8 +14783,6 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{ size.x * $.pixelDensityRatio, size.y * $.pixelDensityRatio ); - - context.restore(); }, /** @@ -15357,6 +14799,7 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{ this.element = null; this.imgElement = null; + this.image = null; this.loaded = false; this.loading = false; } @@ -15616,8 +15059,8 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{ this.adjust( position, size ); - position = position.apply( Math.round ); - size = size.apply( Math.round ); + position = position.apply( Math.floor ); + size = size.apply( Math.ceil ); // rotate the position of the overlay // TODO only rotate overlays if in canvas mode @@ -15648,10 +15091,7 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{ style.left = position.x + "px"; style.top = position.y + "px"; style.position = "absolute"; - - if (style.display != 'none') { - style.display = 'block'; - } + style.display = 'block'; if ( scales ) { style.width = size.x + "px"; @@ -16173,18 +15613,29 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{ // private _offsetForRotation: function( tile, degrees, useSketch ){ var cx = this.canvas.width / 2, - cy = this.canvas.height / 2; + cy = this.canvas.height / 2, + px = tile.position.x - cx, + py = tile.position.y - cy; var context = this._getContext( useSketch ); context.save(); context.translate(cx, cy); context.rotate( Math.PI / 180 * degrees); - context.translate(-cx, -cy); + tile.position.x = px; + tile.position.y = py; }, // private _restoreRotationChanges: function( tile, useSketch ){ + var cx = this.canvas.width / 2, + cy = this.canvas.height / 2, + px = tile.position.x + cx, + py = tile.position.y + cy; + + tile.position.x = px; + tile.position.y = py; + var context = this._getContext( useSketch ); context.restore(); }, @@ -16315,7 +15766,10 @@ $.Viewport = function( options ) { }, options ); - this._updateContainerInnerSize(); + this._containerInnerSize = new $.Point( + Math.max(1, this.containerSize.x - (this._margins.left + this._margins.right)), + Math.max(1, this.containerSize.y - (this._margins.top + this._margins.bottom)) + ); this.centerSpringX = new $.Spring({ initial: 0, @@ -16515,34 +15969,6 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ ); }, - /** - * @function - * The margins push the "home" region in from the sides by the specified amounts. - * @returns {Object} Properties (Numbers, in screen coordinates): left, top, right, bottom. - */ - getMargins: function() { - return $.extend({}, this._margins); // Make a copy so we are not returning our original - }, - - /** - * @function - * The margins push the "home" region in from the sides by the specified amounts. - * @param {Object} margins - Properties (Numbers, in screen coordinates): left, top, right, bottom. - */ - setMargins: function(margins) { - $.console.assert($.type(margins) === 'object', '[Viewport.setMargins] margins must be an object'); - - this._margins = $.extend({ - left: 0, - top: 0, - right: 0, - bottom: 0 - }, margins); - - this._updateContainerInnerSize(); - this.viewer.forceRedraw(); - }, - /** * @function * @param {Boolean} current - Pass true for the current location; defaults to false (target location). @@ -17059,7 +16485,10 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ this.containerSize.x = newContainerSize.x; this.containerSize.y = newContainerSize.y; - this._updateContainerInnerSize(); + this._containerInnerSize = new $.Point( + Math.max(1, newContainerSize.x - (this._margins.left + this._margins.right)), + Math.max(1, newContainerSize.y - (this._margins.top + this._margins.bottom)) + ); if ( maintain ) { // TODO: widthDeltaFactor will always be 1; probably not what's intended @@ -17089,14 +16518,6 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ return this.fitBounds( newBounds, true ); }, - // private - _updateContainerInnerSize: function() { - this._containerInnerSize = new $.Point( - Math.max(1, this.containerSize.x - (this._margins.left + this._margins.right)), - Math.max(1, this.containerSize.y - (this._margins.top + this._margins.bottom)) - ); - }, - /** * @function */ @@ -17612,7 +17033,6 @@ $.TiledImage = function( options ) { lastResetTime: 0, // Last time for which the tiledImage was reset. _midDraw: false, // Is the tiledImage currently updating the viewport? _needsDraw: true, // Does the tiledImage need to update the viewport again? - _hasOpaqueTile: false, // Do we have even one fully opaque tile? //configurable settings springStiffness: $.DEFAULT_SETTINGS.springStiffness, @@ -17889,83 +17309,6 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag ); }, - /** - * Convert pixel coordinates relative to the viewer element to image - * coordinates. - * @param {OpenSeadragon.Point} pixel - * @returns {OpenSeadragon.Point} - */ - viewerElementToImageCoordinates: function( pixel ) { - var point = this.viewport.pointFromPixel( pixel, true ); - return this.viewportToImageCoordinates( point ); - }, - - /** - * Convert pixel coordinates relative to the image to - * viewer element coordinates. - * @param {OpenSeadragon.Point} pixel - * @returns {OpenSeadragon.Point} - */ - imageToViewerElementCoordinates: function( pixel ) { - var point = this.imageToViewportCoordinates( pixel ); - return this.viewport.pixelFromPoint( point, true ); - }, - - /** - * Convert pixel coordinates relative to the window to image coordinates. - * @param {OpenSeadragon.Point} pixel - * @returns {OpenSeadragon.Point} - */ - windowToImageCoordinates: function( pixel ) { - var viewerCoordinates = pixel.minus( - OpenSeadragon.getElementPosition( this.viewer.element )); - return this.viewerElementToImageCoordinates( viewerCoordinates ); - }, - - /** - * Convert image coordinates to pixel coordinates relative to the window. - * @param {OpenSeadragon.Point} pixel - * @returns {OpenSeadragon.Point} - */ - imageToWindowCoordinates: function( pixel ) { - var viewerCoordinates = this.imageToViewerElementCoordinates( pixel ); - return viewerCoordinates.plus( - OpenSeadragon.getElementPosition( this.viewer.element )); - }, - - /** - * Convert a viewport zoom to an image zoom. - * Image zoom: ratio of the original image size to displayed image size. - * 1 means original image size, 0.5 half size... - * Viewport zoom: ratio of the displayed image's width to viewport's width. - * 1 means identical width, 2 means image's width is twice the viewport's width... - * @function - * @param {Number} viewportZoom The viewport zoom - * @returns {Number} imageZoom The image zoom - */ - viewportToImageZoom: function( viewportZoom ) { - var ratio = this._scaleSpring.current.value * - this.viewport._containerInnerSize.x / this.source.dimensions.x; - return ratio * viewportZoom ; - }, - - /** - * Convert an image zoom to a viewport zoom. - * Image zoom: ratio of the original image size to displayed image size. - * 1 means original image size, 0.5 half size... - * Viewport zoom: ratio of the displayed image's width to viewport's width. - * 1 means identical width, 2 means image's width is twice the viewport's width... - * Note: not accurate with multi-image. - * @function - * @param {Number} imageZoom The image zoom - * @returns {Number} viewportZoom The viewport zoom - */ - imageToViewportZoom: function( imageZoom ) { - var ratio = this._scaleSpring.current.value * - this.viewport._containerInnerSize.x / this.source.dimensions.x; - return imageZoom / ratio; - }, - /** * Sets the TiledImage's position in the world. * @param {OpenSeadragon.Point} position - The new position, in viewport coordinates. @@ -17984,7 +17327,6 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag this._xSpring.resetTo(position.x); this._ySpring.resetTo(position.y); - this._needsDraw = true; } else { if (sameTarget) { return; @@ -17992,7 +17334,6 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag this._xSpring.springTo(position.x); this._ySpring.springTo(position.y); - this._needsDraw = true; } if (!sameTarget) { @@ -18075,7 +17416,6 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag this._scaleSpring.resetTo(scale); this._updateForScale(); - this._needsDraw = true; } else { if (sameTarget) { return; @@ -18083,7 +17423,6 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag this._scaleSpring.springTo(scale); this._updateForScale(); - this._needsDraw = true; } if (!sameTarget) { @@ -18277,8 +17616,10 @@ function updateViewport( tiledImage ) { drawTiles( tiledImage, tiledImage.lastDrawn ); // Load the new 'best' tile - if (best && !best.context2D) { + if ( best ) { loadTile( tiledImage, best, currentTime ); + // because we haven't finished drawing, so + tiledImage._needsDraw = true; } } @@ -18422,14 +17763,15 @@ function updateTile( tiledImage, drawLevel, haveDrawn, x, y, level, levelOpacity ); if (!tile.loaded) { - if (tile.context2D) { - setTileLoaded(tiledImage, tile); - } else { - var imageRecord = tiledImage._tileCache.getImageRecord(tile.url); - if (imageRecord) { - var image = imageRecord.getImage(); - setTileLoaded(tiledImage, tile, image); - } + var imageRecord = tiledImage._tileCache.getImageRecord(tile.url); + if (imageRecord) { + tile.loaded = true; + tile.image = imageRecord.getImage(); + + tiledImage._tileCache.cacheTile({ + tile: tile, + tiledImage: tiledImage + }); } } @@ -18462,7 +17804,6 @@ function getTile( x, y, level, tileSource, tilesMatrix, time, numTiles, worldWid bounds, exists, url, - context2D, tile; if ( !tilesMatrix[ level ] ) { @@ -18478,8 +17819,6 @@ function getTile( x, y, level, tileSource, tilesMatrix, time, numTiles, worldWid bounds = tileSource.getTileBounds( level, xMod, yMod ); exists = tileSource.tileExists( level, xMod, yMod ); url = tileSource.getTileUrl( level, xMod, yMod ); - context2D = tileSource.getContext2D ? - tileSource.getContext2D(level, xMod, yMod) : undefined; bounds.x += ( x - xMod ) / numTiles.x; bounds.y += (worldHeight / worldWidth) * (( y - yMod ) / numTiles.y); @@ -18490,8 +17829,7 @@ function getTile( x, y, level, tileSource, tilesMatrix, time, numTiles, worldWid y, bounds, exists, - url, - context2D + url ); } @@ -18506,8 +17844,8 @@ function loadTile( tiledImage, tile, time ) { tiledImage._imageLoader.addJob({ src: tile.url, crossOriginPolicy: tiledImage.crossOriginPolicy, - callback: function( image, errorMsg ){ - onTileLoad( tiledImage, tile, time, image, errorMsg ); + callback: function( image ){ + onTileLoad( tiledImage, tile, time, image ); }, abort: function() { tile.loading = false; @@ -18515,21 +17853,9 @@ function loadTile( tiledImage, tile, time ) { }); } -function onTileLoad( tiledImage, tile, time, image, errorMsg ) { +function onTileLoad( tiledImage, tile, time, image ) { if ( !image ) { - $.console.log( "Tile %s failed to load: %s - error: %s", tile, tile.url, errorMsg ); - /** - * Triggered when a tile fails to load. - * - * @event tile-load-failed - * @memberof OpenSeadragon.Viewer - * @type {object} - * @property {OpenSeadragon.Tile} tile - The tile that failed to load. - * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image the tile belongs to. - * @property {number} time - The time in milliseconds when the tile load began. - * @property {string} message - The error message. - */ - tiledImage.viewer.raiseEvent("tile-load-failed", {tile: tile, tiledImage: tiledImage, time: time, message: errorMsg}); + $.console.log( "Tile %s failed to load: %s", tile, tile.url ); if( !tiledImage.debugMode ){ tile.loading = false; tile.exists = false; @@ -18542,9 +17868,16 @@ function onTileLoad( tiledImage, tile, time, image, errorMsg ) { } var finish = function() { - var cutoff = Math.ceil( Math.log( - tiledImage.source.getTileWidth(tile.level) ) / Math.log( 2 ) ); - setTileLoaded(tiledImage, tile, image, cutoff); + tile.loading = false; + tile.loaded = true; + tile.image = image; + + var cutoff = Math.ceil( Math.log( tiledImage.source.getTileSize(tile.level) ) / Math.log( 2 ) ); + tiledImage._tileCache.cacheTile({ + tile: tile, + cutoff: cutoff, + tiledImage: tiledImage + }); }; // Check if we're mid-update; this can happen on IE8 because image load events for @@ -18555,58 +17888,11 @@ function onTileLoad( tiledImage, tile, time, image, errorMsg ) { // Wait until after the update, in case caching unloads any tiles window.setTimeout( finish, 1); } -} - -function setTileLoaded(tiledImage, tile, image, cutoff) { - var increment = 0; - - function getCompletionCallback() { - increment++; - return completionCallback; - } - function completionCallback() { - increment--; - if (increment === 0) { - tile.loading = false; - tile.loaded = true; - if (!tile.context2D) { - tiledImage._tileCache.cacheTile({ - image: image, - tile: tile, - cutoff: cutoff, - tiledImage: tiledImage - }); - } - tiledImage._needsDraw = true; - } - } - - /** - * Triggered when a tile has just been loaded in memory. That means that the - * image has been downloaded and can be modified before being drawn to the canvas. - * - * @event tile-loaded - * @memberof OpenSeadragon.Viewer - * @type {object} - * @property {Image} image - The image of the tile. - * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image of the loaded tile. - * @property {OpenSeadragon.Tile} tile - The tile which has been loaded. - * @property {function} getCompletionCallback - A function giving a callback to call - * when the asynchronous processing of the image is done. The image will be - * marked as entirely loaded when the callback has been called once for each - * call to getCompletionCallback. - */ - tiledImage.viewer.raiseEvent("tile-loaded", { - tile: tile, - tiledImage: tiledImage, - image: image, - getCompletionCallback: getCompletionCallback - }); - // In case the completion callback is never called, we at least force it once. - getCompletionCallback()(); + tiledImage._needsDraw = true; } + function positionTile( tile, overlap, viewport, viewportCenter, levelVisibility, tiledImage ){ var boundsTL = tile.bounds.getTopLeft(); @@ -18660,7 +17946,6 @@ function blendTile( tiledImage, tile, x, y, level, levelOpacity, currentTime ){ if ( opacity == 1 ) { setCoverage( tiledImage.coverage, level, x, y, true ); - tiledImage._hasOpaqueTile = true; } else if ( deltaTime < blendTimeMillis ) { return true; } @@ -18809,7 +18094,7 @@ function drawTiles( tiledImage, lastDrawn ) { usedClip = true; } - if ( tiledImage.placeholderFillStyle && tiledImage._hasOpaqueTile === false ) { + if ( tiledImage.placeholderFillStyle && lastDrawn.length === 0 ) { var placeholderRect = tiledImage._drawer.viewportToDrawerRectangle(tiledImage.getBounds(true)); var fillStyle = null; @@ -18937,23 +18222,10 @@ ImageRecord.prototype = { }, getRenderedContext: function() { - if (!this._renderedContext) { - var canvas = document.createElement( 'canvas' ); - canvas.width = this._image.width; - canvas.height = this._image.height; - this._renderedContext = canvas.getContext('2d'); - this._renderedContext.drawImage( this._image, 0, 0 ); - //since we are caching the prerendered image on a canvas - //allow the image to not be held in memory - this._image = null; - } return this._renderedContext; }, setRenderedContext: function(renderedContext) { - $.console.error("ImageRecord.setRenderedContext is deprecated. " + - "The rendered context should be created by the ImageRecord " + - "itself when calling ImageRecord.getRenderedContext."); this._renderedContext = renderedContext; }, @@ -19013,7 +18285,6 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{ * may temporarily surpass that number, but should eventually come back down to the max specified. * @param {Object} options - Tile info. * @param {OpenSeadragon.Tile} options.tile - The tile to cache. - * @param {Image} options.image - The image of the tile to cache. * @param {OpenSeadragon.TiledImage} options.tiledImage - The TiledImage that owns that tile. * @param {Number} [options.cutoff=0] - If adding this tile goes over the cache max count, this * function will release an old tile. The cutoff option specifies a tile level at or below which @@ -19023,6 +18294,7 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{ $.console.assert( options, "[TileCache.cacheTile] options is required" ); $.console.assert( options.tile, "[TileCache.cacheTile] options.tile is required" ); $.console.assert( options.tile.url, "[TileCache.cacheTile] options.tile.url is required" ); + $.console.assert( options.tile.image, "[TileCache.cacheTile] options.tile.image is required" ); $.console.assert( options.tiledImage, "[TileCache.cacheTile] options.tiledImage is required" ); var cutoff = options.cutoff || 0; @@ -19030,9 +18302,8 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{ var imageRecord = this._imagesLoaded[options.tile.url]; if (!imageRecord) { - $.console.assert( options.image, "[TileCache.cacheTile] options.image is required to create an ImageRecord" ); imageRecord = this._imagesLoaded[options.tile.url] = new ImageRecord({ - image: options.image + image: options.tile.image }); this._imagesLoadedCount++; @@ -19046,7 +18317,6 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{ if ( this._imagesLoadedCount > this._maxImageCacheCount ) { var worstTile = null; var worstTileIndex = -1; - var worstTileRecord = null; var prevTile, worstTime, worstLevel, prevTime, prevLevel, prevTileRecord; for ( var i = this._tilesLoaded.length - 1; i >= 0; i-- ) { @@ -19058,7 +18328,6 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{ } else if ( !worstTile ) { worstTile = prevTile; worstTileIndex = i; - worstTileRecord = prevTileRecord; continue; } @@ -19071,12 +18340,11 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{ ( prevTime == worstTime && prevLevel > worstLevel ) ) { worstTile = prevTile; worstTileIndex = i; - worstTileRecord = prevTileRecord; } } if ( worstTile && worstTileIndex >= 0 ) { - this._unloadTile(worstTileRecord); + this._unloadTile(worstTile); insertionIndex = worstTileIndex; } } @@ -19097,7 +18365,7 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{ for ( var i = 0; i < this._tilesLoaded.length; ++i ) { tileRecord = this._tilesLoaded[ i ]; if ( tileRecord.tiledImage === tiledImage ) { - this._unloadTile(tileRecord); + this._unloadTile(tileRecord.tile); this._tilesLoaded.splice( i, 1 ); i--; } @@ -19111,11 +18379,8 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{ }, // private - _unloadTile: function(tileRecord) { - $.console.assert(tileRecord, '[TileCache._unloadTile] tileRecord is required'); - var tile = tileRecord.tile; - var tiledImage = tileRecord.tiledImage; - + _unloadTile: function(tile) { + $.console.assert(tile, '[TileCache._unloadTile] tile is required'); tile.unload(); tile.cacheImageRecord = null; @@ -19126,20 +18391,6 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{ delete this._imagesLoaded[tile.url]; this._imagesLoadedCount--; } - - /** - * Triggered when a tile has just been unloaded from memory. - * - * @event tile-unloaded - * @memberof OpenSeadragon.Viewer - * @type {object} - * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image of the unloaded tile. - * @property {OpenSeadragon.Tile} tile - The tile which has been unloaded. - */ - tiledImage.viewer.raiseEvent("tile-unloaded", { - tile: tile, - tiledImage: tiledImage - }); } }; @@ -19199,14 +18450,8 @@ $.World = function( options ) { this.viewer = options.viewer; this._items = []; this._needsDraw = false; - this._autoRefigureSizes = true; - this._needsSizesFigured = false; this._delegatedFigureSizes = function(event) { - if (_this._autoRefigureSizes) { - _this._figureSizes(); - } else { - _this._needsSizesFigured = true; - } + _this._figureSizes(); }; this._figureSizes(); @@ -19232,12 +18477,7 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W this._items.push( item ); } - if (this._autoRefigureSizes) { - this._figureSizes(); - } else { - this._needsSizesFigured = true; - } - + this._figureSizes(); this._needsDraw = true; item.addHandler('bounds-change', this._delegatedFigureSizes); @@ -19354,8 +18594,6 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W * @fires OpenSeadragon.World.event:metrics-change */ removeAll: function() { - // We need to make sure any pending images are canceled so the world items don't get messed up - this.viewer._cancelPendingImages(); var item; for (var i = 0; i < this._items.length; i++) { item = this._items[i]; @@ -19435,28 +18673,12 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W return this._contentFactor; }, - /** - * As a performance optimization, setting this flag to false allows the bounds-change event handler - * on tiledImages to skip calculations on the world bounds. If a lot of images are going to be positioned in - * rapid succession, this is a good idea. When finished, setAutoRefigureSizes should be called with true - * or the system may behave oddly. - * @param {Boolean} [value] The value to which to set the flag. - */ - setAutoRefigureSizes: function(value) { - this._autoRefigureSizes = value; - if (value & this._needsSizesFigured) { - this._figureSizes(); - this._needsSizesFigured = false; - } - }, - /** * Arranges all of the TiledImages with the specified settings. * @param {Object} options - Specifies how to arrange. * @param {Boolean} [options.immediately=false] - Whether to animate to the new arrangement. * @param {String} [options.layout] - See collectionLayout in {@link OpenSeadragon.Options}. * @param {Number} [options.rows] - See collectionRows in {@link OpenSeadragon.Options}. - * @param {Number} [options.columns] - See collectionColumns in {@link OpenSeadragon.Options}. * @param {Number} [options.tileSize] - See collectionTileSize in {@link OpenSeadragon.Options}. * @param {Number} [options.tileMargin] - See collectionTileMargin in {@link OpenSeadragon.Options}. * @fires OpenSeadragon.World.event:metrics-change @@ -19466,21 +18688,13 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W var immediately = options.immediately || false; var layout = options.layout || $.DEFAULT_SETTINGS.collectionLayout; var rows = options.rows || $.DEFAULT_SETTINGS.collectionRows; - var columns = options.columns || $.DEFAULT_SETTINGS.collectionColumns; var tileSize = options.tileSize || $.DEFAULT_SETTINGS.collectionTileSize; var tileMargin = options.tileMargin || $.DEFAULT_SETTINGS.collectionTileMargin; var increment = tileSize + tileMargin; - var wrap; - if (!options.rows && columns) { - wrap = columns; - } else { - wrap = Math.ceil(this._items.length / rows); - } + var wrap = Math.ceil(this._items.length / rows); var x = 0; var y = 0; var item, box, width, height, position; - - this.setAutoRefigureSizes(false); for (var i = 0; i < this._items.length; i++) { if (i && (i % wrap) === 0) { if (layout === 'horizontal') { @@ -19513,7 +18727,6 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W y += increment; } } - this.setAutoRefigureSizes(true); }, // private diff --git a/js/openseadragon/openseadragon-bin-2.0.0/openseadragon.min.js b/js/openseadragon/openseadragon-bin-2.0.0/openseadragon.min.js index c214e0966..3a07e79d0 100644 --- a/js/openseadragon/openseadragon-bin-2.0.0/openseadragon.min.js +++ b/js/openseadragon/openseadragon-bin-2.0.0/openseadragon.min.js @@ -1,12 +1,12 @@ -//! openseadragon 2.1.0 -//! Built on 2015-12-01 -//! Git commit: v2.1.0-3-b2c17b5-dirty +//! OpenSeadragon 2.0.0 +//! Built on 2015-05-26 +//! Git commit: v2.0.0-0-472ab42 //! http://openseadragon.github.io //! License: http://openseadragon.github.io/license/ -window.OpenSeadragon=window.OpenSeadragon||function(a){return new OpenSeadragon.Viewer(a)},"function"==typeof define&&define.amd&&define(function(){return window.OpenSeadragon}),function(a){a.version={versionStr:"2.1.0",major:parseInt("2",10),minor:parseInt("1",10),revision:parseInt("0",10)};var b={"[object Boolean]":"boolean","[object Number]":"number","[object String]":"string","[object Function]":"function","[object Array]":"array","[object Date]":"date","[object RegExp]":"regexp","[object Object]":"object"},c=Object.prototype.toString,d=Object.prototype.hasOwnProperty;a.isFunction=function(b){return"function"===a.type(b)},a.isArray=Array.isArray||function(b){return"array"===a.type(b)},a.isWindow=function(a){return a&&"object"==typeof a&&"setInterval"in a},a.type=function(a){return null===a||void 0===a?String(a):b[c.call(a)]||"object"},a.isPlainObject=function(b){if(!b||"object"!==OpenSeadragon.type(b)||b.nodeType||a.isWindow(b))return!1;if(b.constructor&&!d.call(b,"constructor")&&!d.call(b.constructor.prototype,"isPrototypeOf"))return!1;var c;for(var e in b)c=e;return void 0===c||d.call(b,c)},a.isEmptyObject=function(a){for(var b in a)return!1;return!0},a.supportsCanvas=function(){var b=document.createElement("canvas");return!(!a.isFunction(b.getContext)||!b.getContext("2d"))}(),a.isCanvasTainted=function(a){var b=!1;try{a.getContext("2d").getImageData(0,0,1,1)}catch(c){b=!0}return b},a.pixelDensityRatio=function(){if(a.supportsCanvas){var b=document.createElement("canvas").getContext("2d"),c=window.devicePixelRatio||1,d=b.webkitBackingStorePixelRatio||b.mozBackingStorePixelRatio||b.msBackingStorePixelRatio||b.oBackingStorePixelRatio||b.backingStorePixelRatio||1;return c/d}return 1}()}(OpenSeadragon),function($){function getOffsetParent(a,b){return b&&a!=document.body?document.body:a.offsetParent}function processDZIResponse(a,b){var c,d,e=null;if(!a)throw new Error($.getString("Errors.Security"));if(200!==a.status&&0!==a.status)throw c=a.status,d=404==c?"Not Found":a.statusText,new Error($.getString("Errors.Status",c,d));return a.responseXML&&a.responseXML.documentElement?e=a.responseXML:a.responseText&&(e=$.parseXml(a.responseText)),processDZIXml(e,b)}function processDZIXml(a,b){if(!a||!a.documentElement)throw new Error($.getString("Errors.Xml"));var c=a.documentElement,d=c.tagName;if("Image"==d)try{return processDZI(c,b)}catch(e){throw e instanceof Error?e:new Error($.getString("Errors.Dzi"))}else{if("Collection"==d)throw new Error($.getString("Errors.Dzc"));if("Error"==d)return $._processDZIError(c)}throw new Error($.getString("Errors.Dzi"))}function processDZI(a,b){var c,d,e,f=a.getAttribute("Format"),g=a.getElementsByTagName("Size")[0],h=a.getElementsByTagName("DisplayRect"),i=parseInt(g.getAttribute("Width"),10),j=parseInt(g.getAttribute("Height"),10),k=parseInt(a.getAttribute("TileSize"),10),l=parseInt(a.getAttribute("Overlap"),10),m=[];if(!$.imageFormatSupported(f))throw new Error($.getString("Errors.ImageFormat",f.toUpperCase()));for(e=0;ej;j++)if(a=arguments[j],null!==a||void 0!==a)for(b in a)c=g[b],d=a[b],g!==d&&(i&&d&&(OpenSeadragon.isPlainObject(d)||(e=OpenSeadragon.isArray(d)))?(e?(e=!1,f=c&&OpenSeadragon.isArray(c)?c:[]):f=c&&OpenSeadragon.isPlainObject(c)?c:{},g[b]=OpenSeadragon.extend(i,f,d)):void 0!==d&&(g[b]=d));return g},$.extend($,{DEFAULT_SETTINGS:{xmlPath:null,tileSources:null,tileHost:null,initialPage:0,crossOriginPolicy:!1,ajaxWithCredentials:!1,panHorizontal:!0,panVertical:!0,constrainDuringPan:!1,wrapHorizontal:!1,wrapVertical:!1,visibilityRatio:.5,minPixelRatio:.5,defaultZoomLevel:0,minZoomLevel:null,maxZoomLevel:null,homeFillsViewer:!1,clickTimeThreshold:300,clickDistThreshold:5,dblClickTimeThreshold:300,dblClickDistThreshold:20,springStiffness:6.5,animationTime:1.2,gestureSettingsMouse:{scrollToZoom:!0,clickToZoom:!0,dblClickToZoom:!1,pinchToZoom:!1,flickEnabled:!1,flickMinSpeed:120,flickMomentum:.25,pinchRotate:!1},gestureSettingsTouch:{scrollToZoom:!1,clickToZoom:!1,dblClickToZoom:!0,pinchToZoom:!0,flickEnabled:!0,flickMinSpeed:120,flickMomentum:.25,pinchRotate:!1},gestureSettingsPen:{scrollToZoom:!1,clickToZoom:!0,dblClickToZoom:!1,pinchToZoom:!1,flickEnabled:!1,flickMinSpeed:120,flickMomentum:.25,pinchRotate:!1},gestureSettingsUnknown:{scrollToZoom:!1,clickToZoom:!1,dblClickToZoom:!0,pinchToZoom:!0,flickEnabled:!0,flickMinSpeed:120,flickMomentum:.25,pinchRotate:!1},zoomPerClick:2,zoomPerScroll:1.2,zoomPerSecond:1,blendTime:0,alwaysBlend:!1,autoHideControls:!0,immediateRender:!1,minZoomImageRatio:.9,maxZoomPixelRatio:1.1,pixelsPerWheelLine:40,autoResize:!0,preserveImageSizeOnResize:!1,minScrollDeltaTime:50,showSequenceControl:!0,sequenceControlAnchor:null,preserveViewport:!1,preserveOverlays:!1,navPrevNextWrap:!1,showNavigationControl:!0,navigationControlAnchor:null,showZoomControl:!0,showHomeControl:!0,showFullPageControl:!0,showRotationControl:!1,controlsFadeDelay:2e3,controlsFadeLength:1500,mouseNavEnabled:!0,showNavigator:!1,navigatorId:null,navigatorPosition:null,navigatorSizeRatio:.2,navigatorMaintainSizeRatio:!1,navigatorTop:null,navigatorLeft:null,navigatorHeight:null,navigatorWidth:null,navigatorAutoResize:!0,navigatorRotate:!0,degrees:0,opacity:1,placeholderFillStyle:null,showReferenceStrip:!1,referenceStripScroll:"horizontal",referenceStripElement:null,referenceStripHeight:null,referenceStripWidth:null,referenceStripPosition:"BOTTOM_LEFT",referenceStripSizeRatio:.2,collectionRows:3,collectionColumns:0,collectionLayout:"horizontal",collectionMode:!1,collectionTileSize:800,collectionTileMargin:80,imageLoaderLimit:0,maxImageCacheCount:200,timeout:3e4,useCanvas:!0,prefixUrl:"/images/",navImages:{zoomIn:{REST:"zoomin_rest.png",GROUP:"zoomin_grouphover.png",HOVER:"zoomin_hover.png",DOWN:"zoomin_pressed.png"},zoomOut:{REST:"zoomout_rest.png",GROUP:"zoomout_grouphover.png",HOVER:"zoomout_hover.png",DOWN:"zoomout_pressed.png"},home:{REST:"home_rest.png",GROUP:"home_grouphover.png",HOVER:"home_hover.png",DOWN:"home_pressed.png"},fullpage:{REST:"fullpage_rest.png",GROUP:"fullpage_grouphover.png",HOVER:"fullpage_hover.png",DOWN:"fullpage_pressed.png"},rotateleft:{REST:"rotateleft_rest.png",GROUP:"rotateleft_grouphover.png",HOVER:"rotateleft_hover.png",DOWN:"rotateleft_pressed.png"},rotateright:{REST:"rotateright_rest.png",GROUP:"rotateright_grouphover.png",HOVER:"rotateright_hover.png",DOWN:"rotateright_pressed.png"},previous:{REST:"previous_rest.png",GROUP:"previous_grouphover.png",HOVER:"previous_hover.png",DOWN:"previous_pressed.png"},next:{REST:"next_rest.png",GROUP:"next_grouphover.png",HOVER:"next_hover.png",DOWN:"next_pressed.png"}},debugMode:!1,debugGridColor:"#437AB2"},SIGNAL:"----seadragon----",delegate:function(a,b){return function(){var c=arguments;return void 0===c&&(c=[]),b.apply(a,c)}},BROWSERS:{UNKNOWN:0,IE:1,FIREFOX:2,SAFARI:3,CHROME:4,OPERA:5},getElement:function(a){return"string"==typeof a&&(a=document.getElementById(a)),a},getElementPosition:function(a){var b,c,d=new $.Point;for(a=$.getElement(a),b="fixed"==$.getElementStyle(a).position,c=getOffsetParent(a,b);c;)d.x+=a.offsetLeft,d.y+=a.offsetTop,b&&(d=d.plus($.getPageScroll())),a=c,b="fixed"==$.getElementStyle(a).position,c=getOffsetParent(a,b);return d},getElementOffset:function(a){a=$.getElement(a);var b,c,d=a&&a.ownerDocument,e={top:0,left:0};return d?(b=d.documentElement,"undefined"!=typeof a.getBoundingClientRect&&(e=a.getBoundingClientRect()),c=d==d.window?d:9===d.nodeType?d.defaultView||d.parentWindow:!1,new $.Point(e.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0),e.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0))):new $.Point},getElementSize:function(a){return a=$.getElement(a),new $.Point(a.clientWidth,a.clientHeight)},getElementStyle:document.documentElement.currentStyle?function(a){return a=$.getElement(a),a.currentStyle}:function(a){return a=$.getElement(a),window.getComputedStyle(a,"")},pointInElement:function(a,b){a=$.getElement(a);var c=$.getElementOffset(a),d=$.getElementSize(a);return b.x>=c.x&&b.x=c.y},getEvent:function(a){return a?$.getEvent=function(a){return a}:$.getEvent=function(){return window.event},$.getEvent(a)},getMousePosition:function(a){if("number"==typeof a.pageX)$.getMousePosition=function(a){var b=new $.Point;return a=$.getEvent(a),b.x=a.pageX,b.y=a.pageY,b};else{if("number"!=typeof a.clientX)throw new Error("Unknown event mouse position, no known technique.");$.getMousePosition=function(a){var b=new $.Point;return a=$.getEvent(a),b.x=a.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,b.y=a.clientY+document.body.scrollTop+document.documentElement.scrollTop,b}}return $.getMousePosition(a)},getPageScroll:function(){var a=document.documentElement||{},b=document.body||{};if("number"==typeof window.pageXOffset)$.getPageScroll=function(){return new $.Point(window.pageXOffset,window.pageYOffset)};else if(b.scrollLeft||b.scrollTop)$.getPageScroll=function(){return new $.Point(document.body.scrollLeft,document.body.scrollTop)};else{if(!a.scrollLeft&&!a.scrollTop)return new $.Point(0,0);$.getPageScroll=function(){return new $.Point(document.documentElement.scrollLeft,document.documentElement.scrollTop)}}return $.getPageScroll()},setPageScroll:function(a){if("undefined"!=typeof window.scrollTo)$.setPageScroll=function(a){window.scrollTo(a.x,a.y)};else{var b=$.getPageScroll();if(b.x===a.x&&b.y===a.y)return;document.body.scrollLeft=a.x,document.body.scrollTop=a.y;var c=$.getPageScroll();if(c.x!==b.x&&c.y!==b.y)return void($.setPageScroll=function(a){document.body.scrollLeft=a.x,document.body.scrollTop=a.y});if(document.documentElement.scrollLeft=a.x,document.documentElement.scrollTop=a.y,c=$.getPageScroll(),c.x!==b.x&&c.y!==b.y)return void($.setPageScroll=function(a){document.documentElement.scrollLeft=a.x,document.documentElement.scrollTop=a.y});$.setPageScroll=function(a){}}return $.setPageScroll(a)},getWindowSize:function(){var a=document.documentElement||{},b=document.body||{};if("number"==typeof window.innerWidth)$.getWindowSize=function(){return new $.Point(window.innerWidth,window.innerHeight)};else if(a.clientWidth||a.clientHeight)$.getWindowSize=function(){return new $.Point(document.documentElement.clientWidth,document.documentElement.clientHeight)};else{if(!b.clientWidth&&!b.clientHeight)throw new Error("Unknown window size, no known technique.");$.getWindowSize=function(){return new $.Point(document.body.clientWidth,document.body.clientHeight)}}return $.getWindowSize()},makeCenteredNode:function(a){a=$.getElement(a);var b=[$.makeNeutralElement("div"),$.makeNeutralElement("div"),$.makeNeutralElement("div")];return $.extend(b[0].style,{display:"table",height:"100%",width:"100%"}),$.extend(b[1].style,{display:"table-row"}),$.extend(b[2].style,{display:"table-cell",verticalAlign:"middle",textAlign:"center"}),b[0].appendChild(b[1]),b[1].appendChild(b[2]),b[2].appendChild(a),b[0]},makeNeutralElement:function(a){var b=document.createElement(a),c=b.style;return c.background="transparent none",c.border="none",c.margin="0px",c.padding="0px",c.position="static",b},now:function(){return Date.now?$.now=Date.now:$.now=function(){return(new Date).getTime()},$.now()},makeTransparentImage:function(a){return $.makeTransparentImage=function(a){var b=$.makeNeutralElement("img");return b.src=a,b},$.Browser.vendor==$.BROWSERS.IE&&$.Browser.version<7&&($.makeTransparentImage=function(a){var b=$.makeNeutralElement("img"),c=null;return c=$.makeNeutralElement("span"),c.style.display="inline-block",b.onload=function(){c.style.width=c.style.width||b.width+"px",c.style.height=c.style.height||b.height+"px",b.onload=null,b=null},b.src=a,c.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+a+"', sizingMethod='scale')",c}),$.makeTransparentImage(a)},setElementOpacity:function(a,b,c){var d,e;a=$.getElement(a),c&&!$.Browser.alpha&&(b=Math.round(b)),$.Browser.opacity?a.style.opacity=1>b?b:"":1>b?(d=Math.round(100*b),e="alpha(opacity="+d+")",a.style.filter=e):a.style.filter=""},setElementTouchActionNone:function(a){a=$.getElement(a),"undefined"!=typeof a.style.touchAction?a.style.touchAction="none":"undefined"!=typeof a.style.msTouchAction&&(a.style.msTouchAction="none")},addClass:function(a,b){a=$.getElement(a),a.className?-1===(" "+a.className+" ").indexOf(" "+b+" ")&&(a.className+=" "+b):a.className=b},indexOf:function(a,b,c){return Array.prototype.indexOf?this.indexOf=function(a,b,c){return a.indexOf(b,c)}:this.indexOf=function(a,b,c){var d,e,f=c?c:0;if(!a)throw new TypeError;if(e=a.length,0===e||f>=e)return-1;for(0>f&&(f=e-Math.abs(f)),d=f;e>d;d++)if(a[d]===b)return d;return-1},this.indexOf(a,b,c)},removeClass:function(a,b){var c,d,e=[];for(a=$.getElement(a),c=a.className.split(/\s+/),d=0;d=0?($.Browser.vendor=$.BROWSERS.FIREFOX,$.Browser.version=parseFloat(c.substring(c.indexOf("Firefox")+8))):c.indexOf("Safari")>=0?($.Browser.vendor=c.indexOf("Chrome")>=0?$.BROWSERS.CHROME:$.BROWSERS.SAFARI,$.Browser.version=parseFloat(c.substring(c.substring(0,c.indexOf("Safari")).lastIndexOf("/")+1,c.indexOf("Safari")))):(a=new RegExp("Trident/.*rv:([0-9]{1,}[.0-9]{0,})"),null!==a.exec(c)&&($.Browser.vendor=$.BROWSERS.IE,$.Browser.version=parseFloat(RegExp.$1))));break;case"Opera":$.Browser.vendor=$.BROWSERS.OPERA,$.Browser.version=parseFloat(b)}var d,e,f,g=window.location.search.substring(1),h=g.split("&");for(f=0;f0&&(URLPARAMS[d.substring(0,e)]=decodeURIComponent(d.substring(e+1)));$.Browser.alpha=!($.Browser.vendor==$.BROWSERS.IE&&$.Browser.version<9||$.Browser.vendor==$.BROWSERS.CHROME&&$.Browser.version<2),$.Browser.opacity=!($.Browser.vendor==$.BROWSERS.IE&&$.Browser.version<9)}();var nullfunction=function(a){};$.console=window.console||{log:nullfunction,debug:nullfunction,info:nullfunction,warn:nullfunction,error:nullfunction,assert:nullfunction},function(a){var b=a.requestAnimationFrame||a.mozRequestAnimationFrame||a.webkitRequestAnimationFrame||a.msRequestAnimationFrame,c=a.cancelAnimationFrame||a.mozCancelAnimationFrame||a.webkitCancelAnimationFrame||a.msCancelAnimationFrame;if(b&&c)$.requestAnimationFrame=function(){return b.apply(a,arguments)},$.cancelAnimationFrame=function(){return c.apply(a,arguments)};else{var d,e=[],f=[],g=0;$.requestAnimationFrame=function(a){return e.push([++g,a]),d||(d=setInterval(function(){if(e.length){var a=$.now(),b=f;for(f=e,e=b;f.length;)f.shift()[1](a)}else clearInterval(d),d=void 0},20)),g},$.cancelAnimationFrame=function(a){var b,c;for(b=0,c=e.length;c>b;b+=1)if(e[b][0]===a)return void e.splice(b,1);for(b=0,c=f.length;c>b;b+=1)if(f[b][0]===a)return void f.splice(b,1)}}}(window),$._processDZIError=function(a){var b=a.getElementsByTagName("Message")[0],c=b.firstChild.nodeValue;throw new Error(c)}}(OpenSeadragon),function(a){var b={supportsFullScreen:!1,isFullScreen:function(){return!1},getFullScreenElement:function(){return null},requestFullScreen:function(){},exitFullScreen:function(){},cancelFullScreen:function(){},fullScreenEventName:"",fullScreenErrorEventName:""};document.exitFullscreen?(b.supportsFullScreen=!0,b.getFullScreenElement=function(){return document.fullscreenElement},b.requestFullScreen=function(a){return a.requestFullscreen()},b.exitFullScreen=function(){document.exitFullscreen()},b.fullScreenEventName="fullscreenchange",b.fullScreenErrorEventName="fullscreenerror"):document.msExitFullscreen?(b.supportsFullScreen=!0,b.getFullScreenElement=function(){return document.msFullscreenElement},b.requestFullScreen=function(a){return a.msRequestFullscreen()},b.exitFullScreen=function(){document.msExitFullscreen()},b.fullScreenEventName="MSFullscreenChange",b.fullScreenErrorEventName="MSFullscreenError"):document.webkitExitFullscreen?(b.supportsFullScreen=!0,b.getFullScreenElement=function(){return document.webkitFullscreenElement},b.requestFullScreen=function(a){return a.webkitRequestFullscreen()},b.exitFullScreen=function(){document.webkitExitFullscreen()},b.fullScreenEventName="webkitfullscreenchange",b.fullScreenErrorEventName="webkitfullscreenerror"):document.webkitCancelFullScreen?(b.supportsFullScreen=!0,b.getFullScreenElement=function(){return document.webkitCurrentFullScreenElement},b.requestFullScreen=function(a){return a.webkitRequestFullScreen()},b.exitFullScreen=function(){document.webkitCancelFullScreen()},b.fullScreenEventName="webkitfullscreenchange",b.fullScreenErrorEventName="webkitfullscreenerror"):document.mozCancelFullScreen&&(b.supportsFullScreen=!0,b.getFullScreenElement=function(){return document.mozFullScreenElement},b.requestFullScreen=function(a){return a.mozRequestFullScreen()},b.exitFullScreen=function(){document.mozCancelFullScreen()},b.fullScreenEventName="mozfullscreenchange",b.fullScreenErrorEventName="mozfullscreenerror"),b.isFullScreen=function(){return null!==b.getFullScreenElement()},b.cancelFullScreen=function(){a.console.error("cancelFullScreen is deprecated. Use exitFullScreen instead."),b.exitFullScreen()},a.extend(a,b)}(OpenSeadragon),function(a){a.EventSource=function(){this.events={}},a.EventSource.prototype={addHandler:function(b,c,d){var e=this.events[b];e||(this.events[b]=e=[]),c&&a.isFunction(c)&&(e[e.length]={handler:c,userData:d||null})},removeHandler:function(b,c){var d,e=this.events[b],f=[];if(e&&a.isArray(e)){for(d=0;dd;d++)b[d]&&(c.eventSource=a,c.userData=b[d].userData,b[d].handler(c))}):null},raiseEvent:function(a,b){var c=this.getHandler(a);c&&(b||(b={}),c(this,b))}}}(OpenSeadragon),function(a){function b(b){var c,d=oa[b.hash],e=d.activePointersLists.length;for(c=0;e>c;c++)d.activePointersLists[c].captureCount>0&&(a.removeEvent(a.MouseTracker.captureElement,"mousemove",d.mousemovecaptured,!0),a.removeEvent(a.MouseTracker.captureElement,"mouseup",d.mouseupcaptured,!0),a.removeEvent(a.MouseTracker.captureElement,a.MouseTracker.unprefixedPointerEvents?"pointermove":"MSPointerMove",d.pointermovecaptured,!0),a.removeEvent(a.MouseTracker.captureElement,a.MouseTracker.unprefixedPointerEvents?"pointerup":"MSPointerUp",d.pointerupcaptured,!0),a.removeEvent(a.MouseTracker.captureElement,"touchmove",d.touchmovecaptured,!0),a.removeEvent(a.MouseTracker.captureElement,"touchend",d.touchendcaptured,!0),d.activePointersLists[c].captureCount=0);for(c=0;e>c;c++)d.activePointersLists.pop()}function c(c){var d,e,f=oa[c.hash];if(!f.tracking){for(e=0;ed;d++)f.push(c.getByIndex(d));f.length>0&&(ja(a,b,f,0),c.captureCount=1,g(a,"touch"),ha(a,b,f))}function M(b,c){var d,e,g,h,j=c.changedTouches.length,k=[],l=b.getActivePointersListByType("touch");for(d=a.now(),l.getLength()>c.touches.length-j&&(a.console.warn("Tracked touch contact count doesn't match event.touches.length. Removing all tracked touch pointers."),L(b,c,l)),e=0;j>e;e++)k.push({id:c.changedTouches[e].identifier,type:"touch",currentPos:i(c.changedTouches[e]),currentTime:d});for(ga(b,c,k),e=0;eg;g++)h.push({id:c.changedTouches[g].identifier,type:"touch",currentPos:i(c.changedTouches[g]),currentTime:d});ga(na[e],c,h)}ia(b,c,k,0)&&(a.stopEvent(c),f(b,"touch")),a.cancelEvent(c)}function N(a,b){P(a,b)}function O(b,c){P(b,c),a.stopEvent(c)}function P(b,c){var d,e,f,h,j=c.changedTouches.length,k=[];for(d=a.now(),e=0;j>e;e++)k.push({id:c.changedTouches[e].identifier,type:"touch",currentPos:i(c.changedTouches[e]),currentTime:d});for(ja(b,c,k,0)&&g(b,"touch"),ha(b,c,k),e=0;ef;f++)h.push({id:c.changedTouches[f].identifier,type:"touch",currentPos:i(c.changedTouches[f]),currentTime:d});ha(na[e],c,h)}a.cancelEvent(c)}function Q(a,b){S(a,b)}function R(b,c){S(b,c),a.stopEvent(c)}function S(b,c){var d,e=c.changedTouches.length,f=[];for(d=0;e>d;d++)f.push({id:c.changedTouches[d].identifier,type:"touch",currentPos:i(c.changedTouches[d]),currentTime:a.now()});ka(b,c,f),a.cancelEvent(c)}function T(a,b){var c=(b.changedTouches.length,a.getActivePointersListByType("touch"));L(a,b,c)}function U(a,b){return b.stopPropagation(), -b.preventDefault(),!1}function V(a,b){return b.stopPropagation(),b.preventDefault(),!1}function W(b,c){var d;c.currentTarget===c.relatedTarget||w(c.currentTarget,c.relatedTarget)||(d={id:c.pointerId,type:h(c),isPrimary:c.isPrimary,currentPos:i(c),currentTime:a.now()},ga(b,c,[d]))}function X(b,c){var d;c.currentTarget===c.relatedTarget||w(c.currentTarget,c.relatedTarget)||(d={id:c.pointerId,type:h(c),isPrimary:c.isPrimary,currentPos:i(c),currentTime:a.now()},ha(b,c,[d]))}function Y(b,c){var d;d={id:c.pointerId,type:h(c),isPrimary:c.isPrimary,currentPos:i(c),currentTime:a.now()},ia(b,c,[d],c.button)&&(a.stopEvent(c),f(b,d.type)),(b.clickHandler||b.dblClickHandler||b.pressHandler||b.dragHandler||b.dragEndHandler||b.pinchHandler)&&a.cancelEvent(c)}function Z(a,b){_(a,b)}function $(b,c){var d=b.getActivePointersListByType(h(c));d.getById(c.pointerId)&&_(b,c),a.stopEvent(c)}function _(b,c){var d;d={id:c.pointerId,type:h(c),isPrimary:c.isPrimary,currentPos:i(c),currentTime:a.now()},ja(b,c,[d],c.button)&&g(b,d.type)}function aa(a,b){ca(a,b)}function ba(b,c){var d=b.getActivePointersListByType(h(c));d.getById(c.pointerId)&&ca(b,c),a.stopEvent(c)}function ca(b,c){var d;d={id:c.pointerId,type:h(c),isPrimary:c.isPrimary,currentPos:i(c),currentTime:a.now()},ka(b,c,[d])}function da(a,b){var c;c={id:b.pointerId,type:h(b)},la(a,b,[c])}function ea(a,b){return b.hasOwnProperty("isPrimary")||(0===a.getLength()?b.isPrimary=!0:b.isPrimary=!1),b.speed=0,b.direction=0,b.contactPos=b.currentPos,b.contactTime=b.currentTime,b.lastPos=b.currentPos,b.lastTime=b.currentTime,a.add(b)}function fa(a,b){var c,d;return a.getById(b.id)?(c=a.removeById(b.id),b.hasOwnProperty("isPrimary")||(d=a.getPrimary(),d||(d=a.getByIndex(0),d&&(d.isPrimary=!0)))):c=a.getLength(),c}function ga(b,c,d){var e,f,g,h,i=b.getActivePointersListByType(d[0].type),j=d.length;for(e=0;j>e;e++)f=d[e],g=i.getById(f.id),g?(g.insideElement=!0,g.lastPos=g.currentPos,g.lastTime=g.currentTime,g.currentPos=f.currentPos,g.currentTime=f.currentTime,f=g):(f.captured=!1,f.insideElementPressed=!1,f.insideElement=!0,ea(i,f)),b.enterHandler&&(h=b.enterHandler({eventSource:b,pointerType:f.type,position:k(f.currentPos,b.element),buttons:i.buttons,pointers:b.getActivePointerCount(),insideElementPressed:f.insideElementPressed,buttonDownAny:0!==i.buttons,isTouchEvent:"touch"===f.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),h===!1&&a.cancelEvent(c))}function ha(b,c,d){var e,f,g,h,i=(oa[b.hash],b.getActivePointersListByType(d[0].type)),j=d.length;for(e=0;j>e;e++)f=d[e],g=i.getById(f.id),g&&(g.captured?(g.insideElement=!1,g.lastPos=g.currentPos,g.lastTime=g.currentTime,g.currentPos=f.currentPos,g.currentTime=f.currentTime):fa(i,g),f=g),b.exitHandler&&(h=b.exitHandler({eventSource:b,pointerType:f.type,position:k(f.currentPos,b.element),buttons:i.buttons,pointers:b.getActivePointerCount(),insideElementPressed:g?g.insideElementPressed:!1,buttonDownAny:0!==i.buttons,isTouchEvent:"touch"===f.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),h===!1&&a.cancelEvent(c))}function ia(b,c,d,e){var f,g,h,i,j=oa[b.hash],m=b.getActivePointersListByType(d[0].type),n=d.length;if("undefined"!=typeof c.buttons?m.buttons=c.buttons:a.Browser.vendor===a.BROWSERS.IE&&a.Browser.version<9?0===e?m.buttons+=1:1===e?m.buttons+=4:2===e?m.buttons+=2:3===e?m.buttons+=8:4===e?m.buttons+=16:5===e&&(m.buttons+=32):0===e?m.buttons|=1:1===e?m.buttons|=4:2===e?m.buttons|=2:3===e?m.buttons|=8:4===e?m.buttons|=16:5===e&&(m.buttons|=32),0!==e)return b.nonPrimaryPressHandler&&(f=b.nonPrimaryPressHandler({eventSource:b,pointerType:d[0].type,position:k(d[0].currentPos,b.element),button:e,buttons:m.buttons,isTouchEvent:"touch"===d[0].type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),f===!1&&a.cancelEvent(c)),!1;for(g=0;n>g;g++)h=d[g],i=m.getById(h.id),i?(i.captured=!0,i.insideElementPressed=!0,i.insideElement=!0,i.contactPos=h.currentPos,i.contactTime=h.currentTime,i.lastPos=i.currentPos,i.lastTime=i.currentTime,i.currentPos=h.currentPos,i.currentTime=h.currentTime,h=i):(h.captured=!0,h.insideElementPressed=!0,h.insideElement=!0,ea(m,h)),m.contacts++,(b.dragHandler||b.dragEndHandler||b.pinchHandler)&&a.MouseTracker.gesturePointVelocityTracker.addPoint(b,h),1===m.contacts?b.pressHandler&&(f=b.pressHandler({eventSource:b,pointerType:h.type,position:k(h.contactPos,b.element),buttons:m.buttons,isTouchEvent:"touch"===h.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),f===!1&&a.cancelEvent(c)):2===m.contacts&&b.pinchHandler&&"touch"===h.type&&(j.pinchGPoints=m.asArray(),j.lastPinchDist=j.currentPinchDist=j.pinchGPoints[0].currentPos.distanceTo(j.pinchGPoints[1].currentPos),j.lastPinchCenter=j.currentPinchCenter=l(j.pinchGPoints[0].currentPos,j.pinchGPoints[1].currentPos));return!0}function ja(b,c,d,e){var f,g,h,i,j,m,n,o=oa[b.hash],p=b.getActivePointersListByType(d[0].type),q=d.length,r=!1,s=!1;if("undefined"!=typeof c.buttons?p.buttons=c.buttons:a.Browser.vendor===a.BROWSERS.IE&&a.Browser.version<9?0===e?p.buttons-=1:1===e?p.buttons-=4:2===e?p.buttons-=2:3===e?p.buttons-=8:4===e?p.buttons-=16:5===e&&(p.buttons-=32):0===e?p.buttons^=-2:1===e?p.buttons^=-5:2===e?p.buttons^=-3:3===e?p.buttons^=-9:4===e?p.buttons^=-17:5===e&&(p.buttons^=-33),0!==e)return b.nonPrimaryReleaseHandler&&(f=b.nonPrimaryReleaseHandler({eventSource:b,pointerType:d[0].type,position:k(d[0].currentPos,b.element),button:e,buttons:p.buttons,isTouchEvent:"touch"===d[0].type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),f===!1&&a.cancelEvent(c)),!1;for(i=0;q>i;i++)j=d[i],m=p.getById(j.id),m&&(m.captured&&(m.captured=!1,r=!0,s=!0),m.lastPos=m.currentPos,m.lastTime=m.currentTime,m.currentPos=j.currentPos,m.currentTime=j.currentTime,m.insideElement||fa(p,m),g=m.currentPos,h=m.currentTime,s?(p.contacts--,(b.dragHandler||b.dragEndHandler||b.pinchHandler)&&a.MouseTracker.gesturePointVelocityTracker.removePoint(b,m),0===p.contacts?(b.releaseHandler&&(f=b.releaseHandler({eventSource:b,pointerType:m.type,position:k(g,b.element),buttons:p.buttons,insideElementPressed:m.insideElementPressed,insideElementReleased:m.insideElement,isTouchEvent:"touch"===m.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),f===!1&&a.cancelEvent(c)),b.dragEndHandler&&!m.currentPos.equals(m.contactPos)&&(f=b.dragEndHandler({eventSource:b,pointerType:m.type,position:k(m.currentPos,b.element),speed:m.speed,direction:m.direction,shift:c.shiftKey,isTouchEvent:"touch"===m.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),f===!1&&a.cancelEvent(c)),(b.clickHandler||b.dblClickHandler)&&m.insideElement&&(n=h-m.contactTime<=b.clickTimeThreshold&&m.contactPos.distanceTo(g)<=b.clickDistThreshold,b.clickHandler&&(f=b.clickHandler({eventSource:b,pointerType:m.type,position:k(m.currentPos,b.element),quick:n,shift:c.shiftKey,isTouchEvent:"touch"===m.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),f===!1&&a.cancelEvent(c)),b.dblClickHandler&&n&&(p.clicks++,1===p.clicks?(o.lastClickPos=g,o.dblClickTimeOut=setTimeout(function(){p.clicks=0},b.dblClickTimeThreshold)):2===p.clicks&&(clearTimeout(o.dblClickTimeOut),p.clicks=0,o.lastClickPos.distanceTo(g)<=b.dblClickDistThreshold&&(f=b.dblClickHandler({eventSource:b,pointerType:m.type,position:k(m.currentPos,b.element),shift:c.shiftKey,isTouchEvent:"touch"===m.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),f===!1&&a.cancelEvent(c)),o.lastClickPos=null)))):2===p.contacts&&b.pinchHandler&&"touch"===m.type&&(o.pinchGPoints=p.asArray(),o.lastPinchDist=o.currentPinchDist=o.pinchGPoints[0].currentPos.distanceTo(o.pinchGPoints[1].currentPos),o.lastPinchCenter=o.currentPinchCenter=l(o.pinchGPoints[0].currentPos,o.pinchGPoints[1].currentPos))):b.releaseHandler&&(f=b.releaseHandler({eventSource:b,pointerType:m.type,position:k(g,b.element),buttons:p.buttons,insideElementPressed:m.insideElementPressed,insideElementReleased:m.insideElement,isTouchEvent:"touch"===m.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),f===!1&&a.cancelEvent(c)));return r}function ka(b,c,d){var e,f,g,h,i,j,m=oa[b.hash],n=b.getActivePointersListByType(d[0].type),o=d.length;for("undefined"!=typeof c.buttons&&(n.buttons=c.buttons),e=0;o>e;e++)f=d[e],g=n.getById(f.id),g?(f.hasOwnProperty("isPrimary")&&(g.isPrimary=f.isPrimary),g.lastPos=g.currentPos,g.lastTime=g.currentTime,g.currentPos=f.currentPos,g.currentTime=f.currentTime):(f.captured=!1,f.insideElementPressed=!1,f.insideElement=!0,ea(n,f));b.stopHandler&&"mouse"===d[0].type&&(clearTimeout(b.stopTimeOut),b.stopTimeOut=setTimeout(function(){ma(b,c,d[0].type)},b.stopDelay)),0===n.contacts?b.moveHandler&&(j=b.moveHandler({eventSource:b,pointerType:d[0].type,position:k(d[0].currentPos,b.element),buttons:n.buttons,isTouchEvent:"touch"===d[0].type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),j===!1&&a.cancelEvent(c)):1===n.contacts?(b.moveHandler&&(g=n.asArray()[0],j=b.moveHandler({eventSource:b,pointerType:g.type,position:k(g.currentPos,b.element),buttons:n.buttons,isTouchEvent:"touch"===g.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),j===!1&&a.cancelEvent(c)),b.dragHandler&&(g=n.asArray()[0],i=g.currentPos.minus(g.lastPos),j=b.dragHandler({eventSource:b,pointerType:g.type,position:k(g.currentPos,b.element),buttons:n.buttons,delta:i,speed:g.speed,direction:g.direction,shift:c.shiftKey,isTouchEvent:"touch"===g.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),j===!1&&a.cancelEvent(c))):2===n.contacts&&(b.moveHandler&&(h=n.asArray(),j=b.moveHandler({eventSource:b,pointerType:h[0].type,position:k(l(h[0].currentPos,h[1].currentPos),b.element),buttons:n.buttons,isTouchEvent:"touch"===h[0].type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),j===!1&&a.cancelEvent(c)),b.pinchHandler&&"touch"===d[0].type&&(i=m.pinchGPoints[0].currentPos.distanceTo(m.pinchGPoints[1].currentPos),i!=m.currentPinchDist&&(m.lastPinchDist=m.currentPinchDist,m.currentPinchDist=i,m.lastPinchCenter=m.currentPinchCenter,m.currentPinchCenter=l(m.pinchGPoints[0].currentPos,m.pinchGPoints[1].currentPos),j=b.pinchHandler({eventSource:b,pointerType:"touch",gesturePoints:m.pinchGPoints,lastCenter:k(m.lastPinchCenter,b.element),center:k(m.currentPinchCenter,b.element),lastDistance:m.lastPinchDist,distance:m.currentPinchDist,shift:c.shiftKey,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),j===!1&&a.cancelEvent(c))))}function la(a,b,c){ja(a,b,c,0),ha(a,b,c)}function ma(a,b,c){a.stopHandler&&a.stopHandler({eventSource:a,pointerType:c,position:j(b,a.element),buttons:a.getActivePointersListByType(c).buttons,isTouchEvent:"touch"===c,originalEvent:b,preventDefaultAction:!1,userData:a.userData})}var na=[],oa={};a.MouseTracker=function(b){na.push(this);var c=arguments;a.isPlainObject(b)||(b={element:c[0],clickTimeThreshold:c[1],clickDistThreshold:c[2]}),this.hash=Math.random(),this.element=a.getElement(b.element),this.clickTimeThreshold=b.clickTimeThreshold||a.DEFAULT_SETTINGS.clickTimeThreshold,this.clickDistThreshold=b.clickDistThreshold||a.DEFAULT_SETTINGS.clickDistThreshold,this.dblClickTimeThreshold=b.dblClickTimeThreshold||a.DEFAULT_SETTINGS.dblClickTimeThreshold,this.dblClickDistThreshold=b.dblClickDistThreshold||a.DEFAULT_SETTINGS.dblClickDistThreshold,this.userData=b.userData||null,this.stopDelay=b.stopDelay||50,this.enterHandler=b.enterHandler||null,this.exitHandler=b.exitHandler||null,this.pressHandler=b.pressHandler||null,this.nonPrimaryPressHandler=b.nonPrimaryPressHandler||null,this.releaseHandler=b.releaseHandler||null,this.nonPrimaryReleaseHandler=b.nonPrimaryReleaseHandler||null,this.moveHandler=b.moveHandler||null,this.scrollHandler=b.scrollHandler||null,this.clickHandler=b.clickHandler||null,this.dblClickHandler=b.dblClickHandler||null,this.dragHandler=b.dragHandler||null,this.dragEndHandler=b.dragEndHandler||null,this.pinchHandler=b.pinchHandler||null,this.stopHandler=b.stopHandler||null,this.keyDownHandler=b.keyDownHandler||null,this.keyUpHandler=b.keyUpHandler||null,this.keyHandler=b.keyHandler||null,this.focusHandler=b.focusHandler||null,this.blurHandler=b.blurHandler||null;var d=this;oa[this.hash]={click:function(a){m(d,a)},dblclick:function(a){n(d,a)},keydown:function(a){o(d,a)},keyup:function(a){p(d,a)},keypress:function(a){q(d,a)},focus:function(a){r(d,a)},blur:function(a){s(d,a)},wheel:function(a){t(d,a)},mousewheel:function(a){u(d,a)},DOMMouseScroll:function(a){u(d,a)},MozMousePixelScroll:function(a){u(d,a)},mouseenter:function(a){x(d,a)},mouseleave:function(a){A(d,a)},mouseover:function(a){y(d,a)},mouseout:function(a){B(d,a)},mousedown:function(a){E(d,a)},mouseup:function(a){F(d,a)},mouseupcaptured:function(a){G(d,a)},mousemove:function(a){I(d,a)},mousemovecaptured:function(a){J(d,a)},touchstart:function(a){M(d,a)},touchend:function(a){N(d,a)},touchendcaptured:function(a){O(d,a)},touchmove:function(a){Q(d,a)},touchmovecaptured:function(a){R(d,a)},touchcancel:function(a){T(d,a)},gesturestart:function(a){U(d,a)},gesturechange:function(a){V(d,a)},pointerover:function(a){W(d,a)},MSPointerOver:function(a){W(d,a)},pointerout:function(a){X(d,a)},MSPointerOut:function(a){X(d,a)},pointerdown:function(a){Y(d,a)},MSPointerDown:function(a){Y(d,a)},pointerup:function(a){Z(d,a)},MSPointerUp:function(a){Z(d,a)},pointermove:function(a){aa(d,a)},MSPointerMove:function(a){aa(d,a)},pointercancel:function(a){da(d,a)},MSPointerCancel:function(a){da(d,a)},pointerupcaptured:function(a){$(d,a)},pointermovecaptured:function(a){ba(d,a)},tracking:!1,activePointersLists:[],lastClickPos:null,dblClickTimeOut:null,pinchGPoints:[],lastPinchDist:0,currentPinchDist:0,lastPinchCenter:null,currentPinchCenter:null},b.startDisabled||this.setTracking(!0)},a.MouseTracker.prototype={destroy:function(){var a;for(d(this),this.element=null,a=0;ac;c++)if(e.activePointersLists[c].type===b)return e.activePointersLists[c];return d=new a.MouseTracker.GesturePointList(b),e.activePointersLists.push(d),d},getActivePointerCount:function(){var a,b=oa[this.hash],c=b.activePointersLists.length,d=0;for(a=0;c>a;a++)d+=b.activePointersLists[a].getLength();return d},enterHandler:function(){},exitHandler:function(){},pressHandler:function(){},nonPrimaryPressHandler:function(){},releaseHandler:function(){},nonPrimaryReleaseHandler:function(){},moveHandler:function(){},scrollHandler:function(){},clickHandler:function(){},dblClickHandler:function(){},dragHandler:function(){},dragEndHandler:function(){},pinchHandler:function(){},stopHandler:function(){},keyDownHandler:function(){},keyUpHandler:function(){},keyHandler:function(){},focusHandler:function(){},blurHandler:function(){}},a.MouseTracker.gesturePointVelocityTracker=function(){var b=[],c=0,d=0,e=function(a,b){return a.hash.toString()+b.type+b.id.toString()},f=function(){var c,e,f,g,h,i,j=b.length,k=a.now();for(g=k-d,d=k,c=0;j>c;c++)e=b[c],f=e.gPoint,f.direction=Math.atan2(f.currentPos.y-e.lastPos.y,f.currentPos.x-e.lastPos.x),h=e.lastPos.distanceTo(f.currentPos),e.lastPos=f.currentPos,i=1e3*h/(g+1),f.speed=.75*i+.25*f.speed},g=function(g,h){var i=e(g,h);b.push({guid:i,gPoint:h,lastPos:h.currentPos}),1===b.length&&(d=a.now(),c=window.setInterval(f,50))},h=function(a,d){var f,g=e(a,d),h=b.length;for(f=0;h>f;f++)if(b[f].guid===g){b.splice(f,1),h--,0===h&&window.clearInterval(c);break}};return{addPoint:g,removePoint:h}}(),a.MouseTracker.captureElement=document,a.MouseTracker.wheelEventName=a.Browser.vendor==a.BROWSERS.IE&&a.Browser.version>8||"onwheel"in document.createElement("div")?"wheel":void 0!==document.onmousewheel?"mousewheel":"DOMMouseScroll",a.MouseTracker.supportsMouseCapture=function(){var b=document.createElement("div");return a.isFunction(b.setCapture)&&a.isFunction(b.releaseCapture)}(),a.MouseTracker.subscribeEvents=["click","dblclick","keydown","keyup","keypress","focus","blur",a.MouseTracker.wheelEventName],"DOMMouseScroll"==a.MouseTracker.wheelEventName&&a.MouseTracker.subscribeEvents.push("MozMousePixelScroll"),window.PointerEvent&&(window.navigator.pointerEnabled||a.Browser.vendor!==a.BROWSERS.IE)?(a.MouseTracker.havePointerEvents=!0,a.MouseTracker.subscribeEvents.push("pointerover","pointerout","pointerdown","pointerup","pointermove","pointercancel"),a.MouseTracker.unprefixedPointerEvents=!0,navigator.maxTouchPoints?a.MouseTracker.maxTouchPoints=navigator.maxTouchPoints:a.MouseTracker.maxTouchPoints=0,a.MouseTracker.haveMouseEnter=!1):window.MSPointerEvent&&window.navigator.msPointerEnabled?(a.MouseTracker.havePointerEvents=!0,a.MouseTracker.subscribeEvents.push("MSPointerOver","MSPointerOut","MSPointerDown","MSPointerUp","MSPointerMove","MSPointerCancel"),a.MouseTracker.unprefixedPointerEvents=!1,navigator.msMaxTouchPoints?a.MouseTracker.maxTouchPoints=navigator.msMaxTouchPoints:a.MouseTracker.maxTouchPoints=0,a.MouseTracker.haveMouseEnter=!1):(a.MouseTracker.havePointerEvents=!1,a.Browser.vendor===a.BROWSERS.IE&&a.Browser.version<9?(a.MouseTracker.subscribeEvents.push("mouseenter","mouseleave"),a.MouseTracker.haveMouseEnter=!0):(a.MouseTracker.subscribeEvents.push("mouseover","mouseout"),a.MouseTracker.haveMouseEnter=!1),a.MouseTracker.subscribeEvents.push("mousedown","mouseup","mousemove"),"ontouchstart"in window&&a.MouseTracker.subscribeEvents.push("touchstart","touchend","touchmove","touchcancel"),"ongesturestart"in window&&a.MouseTracker.subscribeEvents.push("gesturestart","gesturechange"),a.MouseTracker.mousePointerId="legacy-mouse",a.MouseTracker.maxTouchPoints=10),a.MouseTracker.GesturePointList=function(a){this._gPoints=[],this.type=a,this.buttons=0,this.contacts=0,this.clicks=0,this.captureCount=0},a.MouseTracker.GesturePointList.prototype={getLength:function(){return this._gPoints.length},asArray:function(){return this._gPoints},add:function(a){return this._gPoints.push(a)},removeById:function(a){var b,c=this._gPoints.length;for(b=0;c>b;b++)if(this._gPoints[b].id===a){this._gPoints.splice(b,1);break}return this._gPoints.length},getByIndex:function(a){return ab;b++)if(this._gPoints[b].id===a)return this._gPoints[b];return null},getPrimary:function(a){var b,c=this._gPoints.length;for(b=0;c>b;b++)if(this._gPoints[b].isPrimary)return this._gPoints[b];return null}}}(OpenSeadragon),function(a){a.ControlAnchor={NONE:0,TOP_LEFT:1,TOP_RIGHT:2,BOTTOM_RIGHT:3,BOTTOM_LEFT:4,ABSOLUTE:5},a.Control=function(b,c,d){var e=b.parentNode;"number"==typeof c&&(a.console.error("Passing an anchor directly into the OpenSeadragon.Control constructor is deprecated; please use an options object instead. Support for this deprecated variant is scheduled for removal in December 2013"),c={anchor:c}),c.attachToViewer="undefined"==typeof c.attachToViewer?!0:c.attachToViewer,this.autoFade="undefined"==typeof c.autoFade?!0:c.autoFade,this.element=b,this.anchor=c.anchor,this.container=d,this.anchor==a.ControlAnchor.ABSOLUTE?(this.wrapper=a.makeNeutralElement("div"),this.wrapper.style.position="absolute",this.wrapper.style.top="number"==typeof c.top?c.top+"px":c.top,this.wrapper.style.left="number"==typeof c.left?c.left+"px":c.left,this.wrapper.style.height="number"==typeof c.height?c.height+"px":c.height,this.wrapper.style.width="number"==typeof c.width?c.width+"px":c.width,this.wrapper.style.margin="0px",this.wrapper.style.padding="0px",this.element.style.position="relative",this.element.style.top="0px",this.element.style.left="0px",this.element.style.height="100%",this.element.style.width="100%"):(this.wrapper=a.makeNeutralElement("div"),this.wrapper.style.display="inline-block",this.anchor==a.ControlAnchor.NONE&&(this.wrapper.style.width=this.wrapper.style.height="100%")),this.wrapper.appendChild(this.element),c.attachToViewer?this.anchor==a.ControlAnchor.TOP_RIGHT||this.anchor==a.ControlAnchor.BOTTOM_RIGHT?this.container.insertBefore(this.wrapper,this.container.firstChild):this.container.appendChild(this.wrapper):e.appendChild(this.wrapper)},a.Control.prototype={destroy:function(){this.wrapper.removeChild(this.element),this.container.removeChild(this.wrapper)},isVisible:function(){return"none"!=this.wrapper.style.display},setVisible:function(b){this.wrapper.style.display=b?this.anchor==a.ControlAnchor.ABSOLUTE?"block":"inline-block":"none"},setOpacity:function(b){this.element[a.SIGNAL]&&a.Browser.vendor==a.BROWSERS.IE?a.setElementOpacity(this.element,b,!0):a.setElementOpacity(this.wrapper,b,!0)}}}(OpenSeadragon),function(a){function b(a,b){var c,d=a.controls;for(c=d.length-1;c>=0;c--)if(d[c].element==b)return c;return-1}a.ControlDock=function(b){var c,d,e=["topleft","topright","bottomright","bottomleft"];for(a.extend(!0,this,{id:"controldock-"+a.now()+"-"+Math.floor(1e6*Math.random()),container:a.makeNeutralElement("div"),controls:[]},b),this.container.onsubmit=function(){return!1},this.element&&(this.element=a.getElement(this.element),this.element.appendChild(this.container),this.element.style.position="relative",this.container.style.width="100%",this.container.style.height="100%"),d=0;d=0)){switch(d.anchor){case a.ControlAnchor.TOP_RIGHT:e=this.controls.topright,c.style.position="relative",c.style.paddingRight="0px",c.style.paddingTop="0px";break;case a.ControlAnchor.BOTTOM_RIGHT:e=this.controls.bottomright,c.style.position="relative",c.style.paddingRight="0px",c.style.paddingBottom="0px";break;case a.ControlAnchor.BOTTOM_LEFT:e=this.controls.bottomleft,c.style.position="relative",c.style.paddingLeft="0px",c.style.paddingBottom="0px";break;case a.ControlAnchor.TOP_LEFT:e=this.controls.topleft,c.style.position="relative",c.style.paddingLeft="0px",c.style.paddingTop="0px";break;case a.ControlAnchor.ABSOLUTE:e=this.container,c.style.margin="0px",c.style.padding="0px";break;default:case a.ControlAnchor.NONE:e=this.container,c.style.margin="0px",c.style.padding="0px"}this.controls.push(new a.Control(c,d,e)),c.style.display="inline-block"}},removeControl:function(c){c=a.getElement(c);var d=b(this,c);return d>=0&&(this.controls[d].destroy(),this.controls.splice(d,1)),this},clearControls:function(){for(;this.controls.length>0;)this.controls.pop().destroy();return this},areControlsEnabled:function(){var a;for(a=this.controls.length-1;a>=0;a--)if(this.controls[a].isVisible())return!0;return!1},setControlsEnabled:function(a){var b;for(b=this.controls.length-1;b>=0;b--)this.controls[b].setVisible(a);return this}}}(OpenSeadragon),function(a){function b(b){return b=a.getElement(b),new a.Point(0===b.clientWidth?1:b.clientWidth,0===b.clientHeight?1:b.clientHeight)}function c(b,c,d,e){function f(a,b){a.ready?d(a):(a.addHandler("ready",function(){d(a)}),a.addHandler("open-failed",function(a){e({message:a.message,source:b})}))}var g=b;"string"==a.type(c)&&(c.match(/\s*<.*/)?c=a.parseXml(c):c.match(/\s*[\{\[].*/)&&(c=a.parseJSON(c))),setTimeout(function(){if("string"==a.type(c))c=new a.TileSource({url:c,crossOriginPolicy:b.crossOriginPolicy,ajaxWithCredentials:b.ajaxWithCredentials,useCanvas:b.useCanvas,success:function(a){d(a.tileSource)}}),c.addHandler("open-failed",function(a){e(a)});else if(a.isPlainObject(c)||c.nodeType)if(!c.crossOriginPolicy&&b.crossOriginPolicy&&(c.crossOriginPolicy=b.crossOriginPolicy),void 0===c.ajaxWithCredentials&&(c.ajaxWithCredentials=b.ajaxWithCredentials),void 0===c.useCanvas&&(c.useCanvas=b.useCanvas),a.isFunction(c.getTileUrl)){var h=new a.TileSource(c);h.getTileUrl=c.getTileUrl,d(h)}else{var i=a.TileSource.determineType(g,c);if(!i)return void e({message:"Unable to load TileSource",source:c});var j=i.prototype.configure.apply(g,[c]);f(new i(j),c)}else f(c,c)})}function d(b,c){if(c instanceof a.Overlay)return c;var d=null;if(c.element)d=a.getElement(c.element);else{var e=c.id?c.id:"openseadragon-overlay-"+Math.floor(1e7*Math.random());d=a.getElement(c.id),d||(d=document.createElement("a"),d.href="#/overlay/"+e),d.id=e,a.addClass(d,c.className?c.className:"openseadragon-overlay")}var f=c.location;f||(f=c.width&&c.height?void 0!==c.px?b.viewport.imageToViewportRectangle(new a.Rect(c.px,c.py,c.width,c.height)):new a.Rect(c.x,c.y,c.width,c.height):void 0!==c.px?b.viewport.imageToViewportCoordinates(new a.Point(c.px,c.py)):new a.Point(c.x,c.y));var g=c.placement;return g&&"string"===a.type(g)&&(g=a.OverlayPlacement[c.placement.toUpperCase()]),new a.Overlay({element:d,location:f,placement:g,onDraw:c.onDraw,checkResize:c.checkResize})}function e(a,b){var c;for(c=a.length-1;c>=0;c--)if(a[c].element===b)return c;return-1}function f(b,c){return a.requestAnimationFrame(function(){c(b)})}function g(b){a.requestAnimationFrame(function(){i(b)})}function h(b){b.autoHideControls&&(b.controlsShouldFade=!0,b.controlsFadeBeginTime=a.now()+b.controlsFadeDelay,window.setTimeout(function(){g(b)},b.controlsFadeDelay))}function i(b){var c,d,e,f;if(b.controlsShouldFade){for(c=a.now(),d=c-b.controlsFadeBeginTime,e=1-d/b.controlsFadeLength,e=Math.min(1,e),e=Math.max(0,e),f=b.controls.length-1;f>=0;f--)b.controls[f].autoFade&&b.controls[f].setOpacity(e);e>0&&g(b)}}function j(a){var b;for(a.controlsShouldFade=!1,b=a.controls.length-1;b>=0;b--)a.controls[b].setOpacity(1)}function k(){j(this)}function l(){h(this)}function m(b){if(b.preventDefaultAction||b.ctrl||b.alt||b.meta)return!0;switch(b.keyCode){case 38:return b.shift?this.viewport.zoomBy(1.1):this.viewport.panBy(this.viewport.deltaPointsFromPixels(new a.Point(0,-40))),this.viewport.applyConstraints(),!1;case 40:return b.shift?this.viewport.zoomBy(.9):this.viewport.panBy(this.viewport.deltaPointsFromPixels(new a.Point(0,40))),this.viewport.applyConstraints(),!1;case 37:return this.viewport.panBy(this.viewport.deltaPointsFromPixels(new a.Point(-40,0))),this.viewport.applyConstraints(),!1;case 39:return this.viewport.panBy(this.viewport.deltaPointsFromPixels(new a.Point(40,0))),this.viewport.applyConstraints(),!1;default:return!0}}function n(b){if(b.preventDefaultAction||b.ctrl||b.alt||b.meta)return!0;switch(b.keyCode){case 43:case 61:return this.viewport.zoomBy(1.1),this.viewport.applyConstraints(),!1;case 45:return this.viewport.zoomBy(.9),this.viewport.applyConstraints(),!1;case 48:return this.viewport.goHome(),this.viewport.applyConstraints(),!1;case 119:case 87:return b.shift?this.viewport.zoomBy(1.1):this.viewport.panBy(this.viewport.deltaPointsFromPixels(new a.Point(0,-40))),this.viewport.applyConstraints(),!1;case 115:case 83:return b.shift?this.viewport.zoomBy(.9):this.viewport.panBy(this.viewport.deltaPointsFromPixels(new a.Point(0,40))),this.viewport.applyConstraints(),!1;case 97:return this.viewport.panBy(this.viewport.deltaPointsFromPixels(new a.Point(-40,0))),this.viewport.applyConstraints(),!1;case 100:return this.viewport.panBy(this.viewport.deltaPointsFromPixels(new a.Point(40,0))),this.viewport.applyConstraints(),!1;default:return!0}}function o(a){var b,c=document.activeElement==this.canvas;c||this.canvas.focus(),!a.preventDefaultAction&&this.viewport&&a.quick&&(b=this.gestureSettingsByDeviceType(a.pointerType),b.clickToZoom&&(this.viewport.zoomBy(a.shift?1/this.zoomPerClick:this.zoomPerClick,this.viewport.pointFromPixel(a.position,!0)),this.viewport.applyConstraints())),this.raiseEvent("canvas-click",{tracker:a.eventSource,position:a.position,quick:a.quick,shift:a.shift,originalEvent:a.originalEvent})}function p(a){var b;!a.preventDefaultAction&&this.viewport&&(b=this.gestureSettingsByDeviceType(a.pointerType),b.dblClickToZoom&&(this.viewport.zoomBy(a.shift?1/this.zoomPerClick:this.zoomPerClick,this.viewport.pointFromPixel(a.position,!0)),this.viewport.applyConstraints())),this.raiseEvent("canvas-double-click",{tracker:a.eventSource,position:a.position,shift:a.shift,originalEvent:a.originalEvent})}function q(a){var b;!a.preventDefaultAction&&this.viewport&&(b=this.gestureSettingsByDeviceType(a.pointerType),this.panHorizontal||(a.delta.x=0),this.panVertical||(a.delta.y=0),this.viewport.panBy(this.viewport.deltaPointsFromPixels(a.delta.negate()),b.flickEnabled),this.constrainDuringPan&&this.viewport.applyConstraints()),this.raiseEvent("canvas-drag",{tracker:a.eventSource,position:a.position,delta:a.delta,speed:a.speed,direction:a.direction,shift:a.shift,originalEvent:a.originalEvent})}function r(b){var c;if(!b.preventDefaultAction&&this.viewport){if(c=this.gestureSettingsByDeviceType(b.pointerType),c.flickEnabled&&b.speed>=c.flickMinSpeed){var d=c.flickMomentum*b.speed*Math.cos(b.direction-Math.PI/180*this.viewport.degrees),e=c.flickMomentum*b.speed*Math.sin(b.direction-Math.PI/180*this.viewport.degrees),f=this.viewport.pixelFromPoint(this.viewport.getCenter(!0)),g=this.viewport.pointFromPixel(new a.Point(f.x-d,f.y-e));this.panHorizontal||(g.x=f.x),this.panVertical||(g.y=f.y),this.viewport.panTo(g,!1)}this.viewport.applyConstraints()}this.raiseEvent("canvas-drag-end",{tracker:b.eventSource,position:b.position,speed:b.speed,direction:b.direction,shift:b.shift,originalEvent:b.originalEvent})}function s(a){this.raiseEvent("canvas-enter",{tracker:a.eventSource,pointerType:a.pointerType,position:a.position,buttons:a.buttons,pointers:a.pointers,insideElementPressed:a.insideElementPressed,buttonDownAny:a.buttonDownAny,originalEvent:a.originalEvent})}function t(a){this.raiseEvent("canvas-exit",{tracker:a.eventSource,pointerType:a.pointerType,position:a.position,buttons:a.buttons,pointers:a.pointers,insideElementPressed:a.insideElementPressed,buttonDownAny:a.buttonDownAny,originalEvent:a.originalEvent})}function u(a){this.raiseEvent("canvas-press",{tracker:a.eventSource,pointerType:a.pointerType,position:a.position,insideElementPressed:a.insideElementPressed,insideElementReleased:a.insideElementReleased,originalEvent:a.originalEvent})}function v(a){this.raiseEvent("canvas-release",{tracker:a.eventSource,pointerType:a.pointerType,position:a.position,insideElementPressed:a.insideElementPressed,insideElementReleased:a.insideElementReleased,originalEvent:a.originalEvent})}function w(a){this.raiseEvent("canvas-nonprimary-press",{tracker:a.eventSource,position:a.position,pointerType:a.pointerType,button:a.button,buttons:a.buttons,originalEvent:a.originalEvent})}function x(a){this.raiseEvent("canvas-nonprimary-release",{tracker:a.eventSource,position:a.position,pointerType:a.pointerType,button:a.button,buttons:a.buttons,originalEvent:a.originalEvent})}function y(a){var b,c,d,e;if(!a.preventDefaultAction&&this.viewport&&(b=this.gestureSettingsByDeviceType(a.pointerType),b.pinchToZoom&&(c=this.viewport.pointFromPixel(a.center,!0),d=this.viewport.pointFromPixel(a.lastCenter,!0),e=d.minus(c),this.panHorizontal||(e.x=0),this.panVertical||(e.y=0),this.viewport.zoomBy(a.distance/a.lastDistance,c,!0),this.viewport.panBy(e,!0),this.viewport.applyConstraints()),b.pinchRotate)){var f=Math.atan2(a.gesturePoints[0].currentPos.y-a.gesturePoints[1].currentPos.y,a.gesturePoints[0].currentPos.x-a.gesturePoints[1].currentPos.x),g=Math.atan2(a.gesturePoints[0].lastPos.y-a.gesturePoints[1].lastPos.y,a.gesturePoints[0].lastPos.x-a.gesturePoints[1].lastPos.x);this.viewport.setRotation(this.viewport.getRotation()+(f-g)*(180/Math.PI))}return this.raiseEvent("canvas-pinch",{tracker:a.eventSource, -gesturePoints:a.gesturePoints,lastCenter:a.lastCenter,center:a.center,lastDistance:a.lastDistance,distance:a.distance,shift:a.shift,originalEvent:a.originalEvent}),!1}function z(b){var c,d,e,f;return e=a.now(),f=e-this._lastScrollTime,f>this.minScrollDeltaTime?(this._lastScrollTime=e,!b.preventDefaultAction&&this.viewport&&(c=this.gestureSettingsByDeviceType(b.pointerType),c.scrollToZoom&&(d=Math.pow(this.zoomPerScroll,b.scroll),this.viewport.zoomBy(d,this.viewport.pointFromPixel(b.position,!0)),this.viewport.applyConstraints())),this.raiseEvent("canvas-scroll",{tracker:b.eventSource,position:b.position,scroll:b.scroll,shift:b.shift,originalEvent:b.originalEvent}),c&&c.scrollToZoom?!1:void 0):!1}function A(a){V[this.hash].mouseInside=!0,j(this),this.raiseEvent("container-enter",{tracker:a.eventSource,position:a.position,buttons:a.buttons,pointers:a.pointers,insideElementPressed:a.insideElementPressed,buttonDownAny:a.buttonDownAny,originalEvent:a.originalEvent})}function B(a){a.pointers<1&&(V[this.hash].mouseInside=!1,V[this.hash].animating||h(this)),this.raiseEvent("container-exit",{tracker:a.eventSource,position:a.position,buttons:a.buttons,pointers:a.pointers,insideElementPressed:a.insideElementPressed,buttonDownAny:a.buttonDownAny,originalEvent:a.originalEvent})}function C(a){D(a),a.isOpen()?a._updateRequestId=f(a,C):a._updateRequestId=!1}function D(a){if(!a._opening){var c;if(a.autoResize&&(c=b(a.container),!c.equals(V[a.hash].prevContainerSize))){if(a.preserveImageSizeOnResize){var d=V[a.hash].prevContainerSize,e=a.viewport.getBounds(!0),f=c.x-d.x,g=c.y-d.y,i=a.viewport.deltaPointsFromPixels(new OpenSeadragon.Point(f,g),!0);a.viewport.resize(new OpenSeadragon.Point(c.x,c.y),!1),e.width+=i.x,e.height+=i.y,e.x-=i.x/2,e.y-=i.y/2,a.viewport.fitBoundsWithConstraints(e,!0)}else{var k=a.viewport.getBounds(),l=a.viewport.getCenter();E(a,c,k,l)}V[a.hash].prevContainerSize=c,V[a.hash].forceRedraw=!0}var m=a.viewport.update(),n=a.world.update()||m;m&&a.raiseEvent("viewport-change"),a.referenceStrip&&(n=a.referenceStrip.update(a.viewport)||n),!V[a.hash].animating&&n&&(a.raiseEvent("animation-start"),j(a)),(n||V[a.hash].forceRedraw||a.world.needsDraw())&&(F(a),a._drawOverlays(),a.navigator&&a.navigator.update(a.viewport),V[a.hash].forceRedraw=!1,n&&a.raiseEvent("animation")),V[a.hash].animating&&!n&&(a.raiseEvent("animation-finish"),V[a.hash].mouseInside||h(a)),V[a.hash].animating=n}}function E(b,c,d,e){var f=b.viewport;f.resize(c,!0);var g=new a.Rect(e.x-d.width/2,e.y-d.height/2,d.width,d.height);f.fitBoundsWithConstraints(g,!0)}function F(a){a.imageLoader.clear(),a.drawer.clear(),a.world.draw(),a.raiseEvent("update-viewport",{})}function G(a,b){return a?a+b:b}function H(){V[this.hash].lastZoomTime=a.now(),V[this.hash].zoomFactor=this.zoomPerSecond,V[this.hash].zooming=!0,K(this)}function I(){V[this.hash].lastZoomTime=a.now(),V[this.hash].zoomFactor=1/this.zoomPerSecond,V[this.hash].zooming=!0,K(this)}function J(){V[this.hash].zooming=!1}function K(b){a.requestAnimationFrame(a.delegate(b,L))}function L(){var b,c,d;V[this.hash].zooming&&this.viewport&&(b=a.now(),c=b-V[this.hash].lastZoomTime,d=Math.pow(V[this.hash].zoomFactor,c/1e3),this.viewport.zoomBy(d),this.viewport.applyConstraints(),V[this.hash].lastZoomTime=b,K(this))}function M(){this.viewport&&(V[this.hash].zooming=!1,this.viewport.zoomBy(this.zoomPerClick/1),this.viewport.applyConstraints())}function N(){this.viewport&&(V[this.hash].zooming=!1,this.viewport.zoomBy(1/this.zoomPerClick),this.viewport.applyConstraints())}function O(){this.buttons.emulateEnter(),this.buttons.emulateExit()}function P(){this.viewport&&this.viewport.goHome()}function Q(){this.isFullPage()&&!a.isFullScreen()?this.setFullPage(!1):this.setFullScreen(!this.isFullPage()),this.buttons&&this.buttons.emulateExit(),this.fullPageButton.element.focus(),this.viewport&&this.viewport.applyConstraints()}function R(){if(this.viewport){var a=this.viewport.getRotation();0===a?a=270:a-=90,this.viewport.setRotation(a)}}function S(){if(this.viewport){var a=this.viewport.getRotation();270===a?a=0:a+=90,this.viewport.setRotation(a)}}function T(){var a=this._sequenceIndex-1;this.navPrevNextWrap&&0>a&&(a+=this.tileSources.length),this.goToPage(a)}function U(){var a=this._sequenceIndex+1;this.navPrevNextWrap&&a>=this.tileSources.length&&(a=0),this.goToPage(a)}var V={},W=1;a.Viewer=function(c){var d,e=arguments,g=this;if(a.isPlainObject(c)||(c={id:e[0],xmlPath:e.length>1?e[1]:void 0,prefixUrl:e.length>2?e[2]:void 0,controls:e.length>3?e[3]:void 0,overlays:e.length>4?e[4]:void 0}),c.config&&(a.extend(!0,c,c.config),delete c.config),a.extend(!0,this,{id:c.id,hash:c.hash||W++,element:null,container:null,canvas:null,overlays:[],overlaysContainer:null,previousBody:[],customControls:[],source:null,drawer:null,world:null,viewport:null,navigator:null,collectionViewport:null,collectionDrawer:null,navImages:null,buttons:null,profiler:null},a.DEFAULT_SETTINGS,c),"undefined"==typeof this.hash)throw new Error("A hash must be defined, either by specifying options.id or options.hash.");for("undefined"!=typeof V[this.hash]&&a.console.warn("Hash "+this.hash+" has already been used."),V[this.hash]={fsBoundsDelta:new a.Point(1,1),prevContainerSize:null,animating:!1,forceRedraw:!1,mouseInside:!1,group:null,zooming:!1,zoomFactor:null,lastZoomTime:null,fullPage:!1,onfullscreenchange:null},this._sequenceIndex=0,this._firstOpen=!0,this._updateRequestId=null,this._loadQueue=[],this.currentOverlays=[],this._lastScrollTime=a.now(),a.EventSource.call(this),this.addHandler("open-failed",function(b){var c=a.getString("Errors.OpenFailed",b.eventSource,b.message);g._showMessage(c)}),a.ControlDock.call(this,c),this.xmlPath&&(this.tileSources=[this.xmlPath]),this.element=this.element||document.getElementById(this.id),this.canvas=a.makeNeutralElement("div"),this.canvas.className="openseadragon-canvas",function(a){a.width="100%",a.height="100%",a.overflow="hidden",a.position="absolute",a.top="0px",a.left="0px"}(this.canvas.style),a.setElementTouchActionNone(this.canvas),this.canvas.tabIndex=c.tabIndex||0,this.container.className="openseadragon-container",function(a){a.width="100%",a.height="100%",a.position="relative",a.overflow="hidden",a.left="0px",a.top="0px",a.textAlign="left"}(this.container.style),this.container.insertBefore(this.canvas,this.container.firstChild),this.element.appendChild(this.container),this.bodyWidth=document.body.style.width,this.bodyHeight=document.body.style.height,this.bodyOverflow=document.body.style.overflow,this.docOverflow=document.documentElement.style.overflow,this.innerTracker=new a.MouseTracker({element:this.canvas,startDisabled:this.mouseNavEnabled?!1:!0,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,dblClickTimeThreshold:this.dblClickTimeThreshold,dblClickDistThreshold:this.dblClickDistThreshold,keyDownHandler:a.delegate(this,m),keyHandler:a.delegate(this,n),clickHandler:a.delegate(this,o),dblClickHandler:a.delegate(this,p),dragHandler:a.delegate(this,q),dragEndHandler:a.delegate(this,r),enterHandler:a.delegate(this,s),exitHandler:a.delegate(this,t),pressHandler:a.delegate(this,u),releaseHandler:a.delegate(this,v),nonPrimaryPressHandler:a.delegate(this,w),nonPrimaryReleaseHandler:a.delegate(this,x),scrollHandler:a.delegate(this,z),pinchHandler:a.delegate(this,y)}),this.outerTracker=new a.MouseTracker({element:this.container,startDisabled:this.mouseNavEnabled?!1:!0,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,dblClickTimeThreshold:this.dblClickTimeThreshold,dblClickDistThreshold:this.dblClickDistThreshold,enterHandler:a.delegate(this,A),exitHandler:a.delegate(this,B)}),this.toolbar&&(this.toolbar=new a.ControlDock({element:this.toolbar})),this.bindStandardControls(),V[this.hash].prevContainerSize=b(this.container),this.world=new a.World({viewer:this}),this.world.addHandler("add-item",function(a){g.source=g.world.getItemAt(0).source,V[g.hash].forceRedraw=!0,g._updateRequestId||(g._updateRequestId=f(g,C))}),this.world.addHandler("remove-item",function(a){g.world.getItemCount()?g.source=g.world.getItemAt(0).source:g.source=null,V[g.hash].forceRedraw=!0}),this.world.addHandler("metrics-change",function(a){g.viewport&&g.viewport.setHomeBounds(g.world.getHomeBounds(),g.world.getContentFactor())}),this.world.addHandler("item-index-change",function(a){g.source=g.world.getItemAt(0).source}),this.viewport=new a.Viewport({containerSize:V[this.hash].prevContainerSize,springStiffness:this.springStiffness,animationTime:this.animationTime,minZoomImageRatio:this.minZoomImageRatio,maxZoomPixelRatio:this.maxZoomPixelRatio,visibilityRatio:this.visibilityRatio,wrapHorizontal:this.wrapHorizontal,wrapVertical:this.wrapVertical,defaultZoomLevel:this.defaultZoomLevel,minZoomLevel:this.minZoomLevel,maxZoomLevel:this.maxZoomLevel,viewer:this,degrees:this.degrees,navigatorRotate:this.navigatorRotate,homeFillsViewer:this.homeFillsViewer,margins:this.viewportMargins}),this.viewport.setHomeBounds(this.world.getHomeBounds(),this.world.getContentFactor()),this.imageLoader=new a.ImageLoader({jobLimit:this.imageLoaderLimit}),this.tileCache=new a.TileCache({maxImageCacheCount:this.maxImageCacheCount}),this.drawer=new a.Drawer({viewer:this,viewport:this.viewport,element:this.canvas,debugGridColor:this.debugGridColor}),this.overlaysContainer=a.makeNeutralElement("div"),this.canvas.appendChild(this.overlaysContainer),this.drawer.canRotate()||(this.rotateLeft&&(d=this.buttons.buttons.indexOf(this.rotateLeft),this.buttons.buttons.splice(d,1),this.buttons.element.removeChild(this.rotateLeft.element)),this.rotateRight&&(d=this.buttons.buttons.indexOf(this.rotateRight),this.buttons.buttons.splice(d,1),this.buttons.element.removeChild(this.rotateRight.element))),this.showNavigator&&(this.navigator=new a.Navigator({id:this.navigatorId,position:this.navigatorPosition,sizeRatio:this.navigatorSizeRatio,maintainSizeRatio:this.navigatorMaintainSizeRatio,top:this.navigatorTop,left:this.navigatorLeft,width:this.navigatorWidth,height:this.navigatorHeight,autoResize:this.navigatorAutoResize,prefixUrl:this.prefixUrl,viewer:this,navigatorRotate:this.navigatorRotate,crossOriginPolicy:this.crossOriginPolicy})),this.sequenceMode&&this.bindSequenceControls(),this.tileSources&&this.open(this.tileSources),d=0;dd;d++)this.previousBody.push(e.childNodes[0]),e.removeChild(e.childNodes[0]);this.toolbar&&this.toolbar.element&&(this.toolbar.parentNode=this.toolbar.element.parentNode,this.toolbar.nextSibling=this.toolbar.element.nextSibling,e.appendChild(this.toolbar.element),a.addClass(this.toolbar.element,"fullpage")),a.addClass(this.element,"fullpage"),e.appendChild(this.element),this.element.style.height=a.getWindowSize().y+"px",this.element.style.width=a.getWindowSize().x+"px",this.toolbar&&this.toolbar.element&&(this.element.style.height=a.getElementSize(this.element).y-a.getElementSize(this.toolbar.element).y+"px"),V[this.hash].fullPage=!0,a.delegate(this,A)({})}else{for(this.element.style.margin=this.elementMargin,this.element.style.padding=this.elementPadding,f.margin=this.bodyMargin,g.margin=this.docMargin,f.padding=this.bodyPadding,g.padding=this.docPadding,f.width=this.bodyWidth,f.height=this.bodyHeight,e.removeChild(this.element),c=this.previousBody.length,d=0;c>d;d++)e.appendChild(this.previousBody.shift());a.removeClass(this.element,"fullpage"),V[this.hash].prevElementParent.insertBefore(this.element,V[this.hash].prevNextSibling),this.toolbar&&this.toolbar.element&&(e.removeChild(this.toolbar.element),a.removeClass(this.toolbar.element,"fullpage"),this.toolbar.parentNode.insertBefore(this.toolbar.element,this.toolbar.nextSibling),delete this.toolbar.parentNode,delete this.toolbar.nextSibling),this.element.style.width=V[this.hash].prevElementWidth,this.element.style.height=V[this.hash].prevElementHeight;var j=0,k=function(){a.setPageScroll(h.pageScroll);var b=a.getPageScroll();j++,(10>j&&b.x!==h.pageScroll.x||b.y!==h.pageScroll.y)&&a.requestAnimationFrame(k)};a.requestAnimationFrame(k),V[this.hash].fullPage=!1,a.delegate(this,B)({})}return this.navigator&&this.viewport&&this.navigator.update(this.viewport),this.raiseEvent("full-page",{fullPage:b}),this},setFullScreen:function(b){var c=this;if(!a.supportsFullScreen)return this.setFullPage(b);if(a.isFullScreen()===b)return this;var d={fullScreen:b,preventDefaultAction:!1};if(this.raiseEvent("pre-full-screen",d),d.preventDefaultAction)return this;if(b){if(this.setFullPage(!0),!this.isFullPage())return this;this.fullPageStyleWidth=this.element.style.width,this.fullPageStyleHeight=this.element.style.height,this.element.style.width="100%",this.element.style.height="100%";var e=function(){var b=a.isFullScreen();b||(a.removeEvent(document,a.fullScreenEventName,e),a.removeEvent(document,a.fullScreenErrorEventName,e),c.setFullPage(!1),c.isFullPage()&&(c.element.style.width=c.fullPageStyleWidth,c.element.style.height=c.fullPageStyleHeight)),c.navigator&&c.viewport&&c.navigator.update(c.viewport),c.raiseEvent("full-screen",{fullScreen:b})};a.addEvent(document,a.fullScreenEventName,e),a.addEvent(document,a.fullScreenErrorEventName,e),a.requestFullScreen(document.body)}else a.exitFullScreen();return this},isVisible:function(){return"hidden"!=this.container.style.visibility},setVisible:function(a){return this.container.style.visibility=a?"":"hidden",this.raiseEvent("visible",{visible:a}),this},addTiledImage:function(b){function d(a){for(var c=0;c-1&&b.index=0&&a=0)return this;var i=d(this,h);return this.currentOverlays.push(i),i.drawHTML(this.overlaysContainer,this.viewport),this.raiseEvent("add-overlay",{element:b,location:h.location,placement:h.placement}),this},updateOverlay:function(b,c,d){var f;return b=a.getElement(b),f=e(this.currentOverlays,b),f>=0&&(this.currentOverlays[f].update(c,d),V[this.hash].forceRedraw=!0,this.raiseEvent("update-overlay",{element:b,location:c,placement:d})),this},removeOverlay:function(b){var c;return b=a.getElement(b),c=e(this.currentOverlays,b),c>=0&&(this.currentOverlays[c].destroy(),this.currentOverlays.splice(c,1),V[this.hash].forceRedraw=!0,this.raiseEvent("remove-overlay",{element:b})),this},clearOverlays:function(){for(;this.currentOverlays.length>0;)this.currentOverlays.pop().destroy();return V[this.hash].forceRedraw=!0,this.raiseEvent("clear-overlay",{}),this},_updateSequenceButtons:function(a){this.nextButton&&(this.tileSources&&this.tileSources.length-1!==a?this.nextButton.enable():this.navPrevNextWrap||this.nextButton.disable()),this.previousButton&&(a>0?this.previousButton.enable():this.navPrevNextWrap||this.previousButton.disable())},_showMessage:function(b){this._hideMessage();var c=a.makeNeutralElement("div");c.appendChild(document.createTextNode(b)),this.messageDiv=a.makeCenteredNode(c),a.addClass(this.messageDiv,"openseadragon-message"),this.container.appendChild(this.messageDiv)},_hideMessage:function(){var a=this.messageDiv;a&&(a.parentNode.removeChild(a),delete this.messageDiv)},gestureSettingsByDeviceType:function(a){switch(a){case"mouse":return this.gestureSettingsMouse;case"touch":return this.gestureSettingsTouch;case"pen":return this.gestureSettingsPen;default:return this.gestureSettingsUnknown}},_drawOverlays:function(){var a,b=this.currentOverlays.length;for(a=0;b>a;a++)this.currentOverlays[a].drawHTML(this.overlaysContainer,this.viewport)},_cancelPendingImages:function(){this._loadQueue=[]}})}(OpenSeadragon),function(a){function b(a){a.quick&&this.viewer.viewport&&(this.viewer.viewport.panTo(this.viewport.pointFromPixel(a.position).rotate(-this.viewer.viewport.degrees,this.viewer.viewport.getHomeBounds().getCenter())),this.viewer.viewport.applyConstraints())}function c(a){this.viewer.viewport&&(this.panHorizontal||(a.delta.x=0),this.panVertical||(a.delta.y=0),this.viewer.viewport.panBy(this.viewport.deltaPointsFromPixels(a.delta)))}function d(a){a.insideElementPressed&&this.viewer.viewport&&this.viewer.viewport.applyConstraints()}function e(a){return this.viewer.raiseEvent("navigator-scroll",{tracker:a.eventSource,position:a.position,scroll:a.scroll,shift:a.shift,originalEvent:a.originalEvent}),!1}function f(a,b){a.style.webkitTransform="rotate("+b+"deg)",a.style.mozTransform="rotate("+b+"deg)",a.style.msTransform="rotate("+b+"deg)",a.style.oTransform="rotate("+b+"deg)",a.style.transform="rotate("+b+"deg)"}a.Navigator=function(g){var h,i,j=g.viewer,k=this;g.id?(this.element=document.getElementById(g.id),g.controlOptions={anchor:a.ControlAnchor.NONE,attachToViewer:!1,autoFade:!1}):(g.id="navigator-"+a.now(),this.element=a.makeNeutralElement("div"),g.controlOptions={anchor:a.ControlAnchor.TOP_RIGHT,attachToViewer:!0,autoFade:!0},g.position&&("BOTTOM_RIGHT"==g.position?g.controlOptions.anchor=a.ControlAnchor.BOTTOM_RIGHT:"BOTTOM_LEFT"==g.position?g.controlOptions.anchor=a.ControlAnchor.BOTTOM_LEFT:"TOP_RIGHT"==g.position?g.controlOptions.anchor=a.ControlAnchor.TOP_RIGHT:"TOP_LEFT"==g.position?g.controlOptions.anchor=a.ControlAnchor.TOP_LEFT:"ABSOLUTE"==g.position&&(g.controlOptions.anchor=a.ControlAnchor.ABSOLUTE,g.controlOptions.top=g.top,g.controlOptions.left=g.left,g.controlOptions.height=g.height,g.controlOptions.width=g.width))),this.element.id=g.id,this.element.className+=" navigator",g=a.extend(!0,{sizeRatio:a.DEFAULT_SETTINGS.navigatorSizeRatio},g,{element:this.element,tabIndex:-1,showNavigator:!1,mouseNavEnabled:!1,showNavigationControl:!1,showSequenceControl:!1,immediateRender:!0,blendTime:0,animationTime:0,autoResize:g.autoResize,minZoomImageRatio:1}),g.minPixelRatio=this.minPixelRatio=j.minPixelRatio,a.setElementTouchActionNone(this.element),this.borderWidth=2,this.fudge=new a.Point(1,1),this.totalBorderWidths=new a.Point(2*this.borderWidth,2*this.borderWidth).minus(this.fudge),g.controlOptions.anchor!=a.ControlAnchor.NONE&&!function(a,b){ -a.margin="0px",a.border=b+"px solid #555",a.padding="0px",a.background="#000",a.opacity=.8,a.overflow="hidden"}(this.element.style,this.borderWidth),this.displayRegion=a.makeNeutralElement("div"),this.displayRegion.id=this.element.id+"-displayregion",this.displayRegion.className="displayregion",function(a,b){a.position="relative",a.top="0px",a.left="0px",a.fontSize="0px",a.overflow="hidden",a.border=b+"px solid #900",a.margin="0px",a.padding="0px",a.background="transparent",a["float"]="left",a.cssFloat="left",a.styleFloat="left",a.zIndex=999999999,a.cursor="default"}(this.displayRegion.style,this.borderWidth),this.displayRegionContainer=a.makeNeutralElement("div"),this.displayRegionContainer.id=this.element.id+"-displayregioncontainer",this.displayRegionContainer.className="displayregioncontainer",this.displayRegionContainer.style.width="100%",this.displayRegionContainer.style.height="100%",j.addControl(this.element,g.controlOptions),this._resizeWithViewer=g.controlOptions.anchor!=a.ControlAnchor.ABSOLUTE&&g.controlOptions.anchor!=a.ControlAnchor.NONE,this._resizeWithViewer&&(g.width&&g.height?(this.element.style.height="number"==typeof g.height?g.height+"px":g.height,this.element.style.width="number"==typeof g.width?g.width+"px":g.width):(h=a.getElementSize(j.element),this.element.style.height=Math.round(h.y*g.sizeRatio)+"px",this.element.style.width=Math.round(h.x*g.sizeRatio)+"px",this.oldViewerSize=h),i=a.getElementSize(this.element),this.elementArea=i.x*i.y),this.oldContainerSize=new a.Point(0,0),a.Viewer.apply(this,[g]),this.displayRegionContainer.appendChild(this.displayRegion),this.element.getElementsByTagName("div")[0].appendChild(this.displayRegionContainer),g.navigatorRotate&&g.viewer.addHandler("rotate",function(a){f(k.displayRegionContainer,a.degrees),f(k.displayRegion,-a.degrees),k.viewport.setRotation(a.degrees)}),this.innerTracker.destroy(),this.innerTracker=new a.MouseTracker({element:this.element,dragHandler:a.delegate(this,c),clickHandler:a.delegate(this,b),releaseHandler:a.delegate(this,d),scrollHandler:a.delegate(this,e)}),this.addHandler("reset-size",function(){k.viewport&&k.viewport.goHome(!0)}),this.addHandler("reset-size",function(){k.viewport&&k.viewport.goHome(!0)}),j.world.addHandler("item-index-change",function(a){var b=k.world.getItemAt(a.previousIndex);k.world.setItemIndex(b,a.newIndex)}),j.world.addHandler("remove-item",function(a){var b=a.item,c=k._getMatchingItem(b);c&&k.world.removeItem(c)}),this.update(j.viewport)},a.extend(a.Navigator.prototype,a.EventSource.prototype,a.Viewer.prototype,{updateSize:function(){if(this.viewport){var b=new a.Point(0===this.container.clientWidth?1:this.container.clientWidth,0===this.container.clientHeight?1:this.container.clientHeight);b.equals(this.oldContainerSize)||(this.viewport.resize(b,!0),this.viewport.goHome(!0),this.oldContainerSize=b,this.drawer.clear(),this.world.draw())}},update:function(b){var c,d,e,f,g,h;if(c=a.getElementSize(this.viewer.element),this._resizeWithViewer&&c.x&&c.y&&!c.equals(this.oldViewerSize)&&(this.oldViewerSize=c,this.maintainSizeRatio||!this.elementArea?(d=c.x*this.sizeRatio,e=c.y*this.sizeRatio):(d=Math.sqrt(this.elementArea*(c.x/c.y)),e=this.elementArea/d),this.element.style.width=Math.round(d)+"px",this.element.style.height=Math.round(e)+"px",this.elementArea||(this.elementArea=d*e),this.updateSize()),b&&this.viewport){f=b.getBounds(!0),g=this.viewport.pixelFromPoint(f.getTopLeft(),!1),h=this.viewport.pixelFromPoint(f.getBottomRight(),!1).minus(this.totalBorderWidths);var i=this.displayRegion.style;i.display=this.world.getItemCount()?"block":"none",i.top=Math.round(g.y)+"px",i.left=Math.round(g.x)+"px";var j=Math.abs(g.x-h.x),k=Math.abs(g.y-h.y);i.width=Math.round(Math.max(j,0))+"px",i.height=Math.round(Math.max(k,0))+"px"}},addTiledImage:function(b){var c=this,d=b.originalTiledImage;delete b.original;var e=a.extend({},b,{success:function(a){var b=a.item;b._originalForNavigator=d,c._matchBounds(b,d,!0),d.addHandler("bounds-change",function(){c._matchBounds(b,d)})}});return a.Viewer.prototype.addTiledImage.apply(this,[e])},_getMatchingItem:function(a){for(var b,c=this.world.getItemCount(),d=0;c>d;d++)if(b=this.world.getItemAt(d),b._originalForNavigator===a)return b;return null},_matchBounds:function(a,b,c){var d=b.getBounds();a.setPosition(d.getTopLeft(),c),a.setWidth(d.width,c)}})}(OpenSeadragon),function(a){var b={Errors:{Dzc:"Sorry, we don't support Deep Zoom Collections!",Dzi:"Hmm, this doesn't appear to be a valid Deep Zoom Image.",Xml:"Hmm, this doesn't appear to be a valid Deep Zoom Image.",ImageFormat:"Sorry, we don't support {0}-based Deep Zoom Images.",Security:"It looks like a security restriction stopped us from loading this Deep Zoom Image.",Status:"This space unintentionally left blank ({0} {1}).",OpenFailed:"Unable to open {0}: {1}"},Tooltips:{FullPage:"Toggle full page",Home:"Go home",ZoomIn:"Zoom in",ZoomOut:"Zoom out",NextPage:"Next page",PreviousPage:"Previous page",RotateLeft:"Rotate left",RotateRight:"Rotate right"}};a.extend(a,{getString:function(c){var d,e=c.split("."),f=null,g=arguments,h=b;for(d=0;d=d.x&&e.y+1>=d.y));c++);return Math.max(0,c-1)},getTileAtPoint:function(b,c){var d=c.times(this.dimensions.x).times(this.getLevelScale(b)),e=Math.floor(d.x/this.getTileWidth(b)),f=Math.floor(d.y/this.getTileHeight(b));return new a.Point(e,f)},getTileBounds:function(b,c,d){var e=this.dimensions.times(this.getLevelScale(b)),f=this.getTileWidth(b),g=this.getTileHeight(b),h=0===c?0:f*c-this.tileOverlap,i=0===d?0:g*d-this.tileOverlap,j=f+(0===c?1:2)*this.tileOverlap,k=g+(0===d?1:2)*this.tileOverlap,l=1/e.x;return j=Math.min(j,e.x-h),k=Math.min(k,e.y-i),new a.Rect(h*l,i*l,j*l,k*l)},getImageInfo:function(c){var d,e,f,g,h,i,j,k=this;c&&(h=c.split("/"),i=h[h.length-1],j=i.lastIndexOf("."),j>-1&&(h[h.length-1]=i.slice(0,j))),e=function(b){"string"==typeof b&&(b=a.parseXml(b));var d=a.TileSource.determineType(k,b,c);return d?(g=d.prototype.configure.apply(k,[b,c]),void 0===g.ajaxWithCredentials&&(g.ajaxWithCredentials=k.ajaxWithCredentials),f=new d(g),k.ready=!0,void k.raiseEvent("ready",{tileSource:f})):void k.raiseEvent("open-failed",{message:"Unable to load TileSource",source:c})},c.match(/\.js$/)?(d=c.split("/").pop().replace(".js",""),a.jsonp({url:c,async:!1,callbackName:d,callback:e})):a.makeAjaxRequest({url:c,withCredentials:this.ajaxWithCredentials,success:function(a){var c=b(a);e(c)},error:function(a,b){var d;try{d="HTTP "+a.status+" attempting to load TileSource"}catch(e){var f;f="undefined"!=typeof b&&b.toString?b.toString():"Unknown error",d=f+" attempting to load TileSource"}k.raiseEvent("open-failed",{message:d,source:c})}})},supports:function(a,b){return!1},configure:function(a,b){throw new Error("Method not implemented.")},getTileUrl:function(a,b,c){throw new Error("Method not implemented.")},tileExists:function(a,b,c){var d=this.getNumTiles(a);return a>=this.minLevel&&a<=this.maxLevel&&b>=0&&c>=0&&b=0;k--)for(l=this.displayRects[k],m=l.minLevel;m<=l.maxLevel;m++)this._levelRects[m]||(this._levelRects[m]=[]),this._levelRects[m].push(l);a.TileSource.apply(this,[n])},a.extend(a.DziTileSource.prototype,a.TileSource.prototype,{supports:function(a,b){var c;return a.Image?c=a.Image.xmlns:a.documentElement&&("Image"==a.documentElement.localName||"Image"==a.documentElement.tagName)&&(c=a.documentElement.namespaceURI),"http://schemas.microsoft.com/deepzoom/2008"==c||"http://schemas.microsoft.com/deepzoom/2009"==c},configure:function(d,e){var f;return f=a.isPlainObject(d)?c(this,d):b(this,d),e&&!f.tilesUrl&&(f.tilesUrl=e.replace(/([^\/]+)\.(dzi|xml|js)(\?.*|$)/,"$1_files/"),-1!=e.search(/\.(dzi|xml|js)\?/)?f.queryParams=e.match(/\?.*/):f.queryParams=""),f},getTileUrl:function(a,b,c){return[this.tilesUrl,a,"/",b,"_",c,".",this.fileFormat,this.queryParams].join("")},tileExists:function(a,b,c){var d,e,f,g,h,i,j,k=this._levelRects[a];if(!k||!k.length)return!0;for(j=k.length-1;j>=0;j--)if(d=k[j],!(ad.maxLevel)&&(e=this.getLevelScale(a),f=d.x*e,g=d.y*e,h=f+d.width*e,i=g+d.height*e,f=Math.floor(f/this.tileSize),g=Math.floor(g/this.tileSize),h=Math.ceil(h/this.tileSize),i=Math.ceil(i/this.tileSize),b>=f&&h>b&&c>=g&&i>c))return!0;return!1}})}(OpenSeadragon),function(a){function b(b){if(!b||!b.documentElement)throw new Error(a.getString("Errors.Xml"));var d=b.documentElement,e=d.tagName,f=null;if("info"==e)try{return f={},c(d,f),f}catch(g){throw g instanceof Error?g:new Error(a.getString("Errors.IIIF"))}throw new Error(a.getString("Errors.IIIF"))}function c(b,d,e){var f,g;if(3==b.nodeType&&e)g=b.nodeValue.trim(),g.match(/^\d*$/)&&(g=Number(g)),d[e]?(a.isArray(d[e])||(d[e]=[d[e]]),d[e].push(g)):d[e]=g;else if(1==b.nodeType)for(f=0;f0?b.tileSize=Math.max.apply(null,h):b.tileSize=f}b.maxLevel||(this.scale_factors?b.maxLevel=Math.floor(Math.pow(Math.max.apply(null,this.scale_factors),.5)):b.maxLevel=Number(Math.ceil(Math.log(Math.max(this.width,this.height),2)))),a.TileSource.apply(this,[b])},a.extend(a.IIIFTileSource.prototype,a.TileSource.prototype,{supports:function(a,b){return a.protocol&&"http://iiif.io/api/image"==a.protocol?!0:!a["@context"]||"http://library.stanford.edu/iiif/image-api/1.1/context.json"!=a["@context"]&&"http://iiif.io/api/image/1/context.json"!=a["@context"]?a.profile&&0===a.profile.indexOf("http://library.stanford.edu/iiif/image-api/compliance.html")?!0:a.identifier&&a.width&&a.height?!0:a.documentElement&&"info"==a.documentElement.tagName&&"http://library.stanford.edu/iiif/image-api/ns/"==a.documentElement.namespaceURI?!0:!1:!0},configure:function(c,d){if(a.isPlainObject(c))return c["@context"]?c:(c["@context"]="http://iiif.io/api/image/1.0/context.json",c["@id"]=d.replace("/info.json",""),c);var e=b(c);return e["@context"]="http://iiif.io/api/image/1.0/context.json",e["@id"]=d.replace("/info.xml",""),e},getTileWidth:function(a){var b=Math.pow(2,this.maxLevel-a);return this.tileSizePerScaleFactor&&this.tileSizePerScaleFactor[b]?this.tileSizePerScaleFactor[b].width:this._tileWidth},getTileHeight:function(a){var b=Math.pow(2,this.maxLevel-a);return this.tileSizePerScaleFactor&&this.tileSizePerScaleFactor[b]?this.tileSizePerScaleFactor[b].height:this._tileHeight},getTileUrl:function(a,b,c){var d,e,f,g,h,i,j,k,l,m,n,o,p="0",q=Math.pow(.5,this.maxLevel-a),r=Math.ceil(this.width*q),s=Math.ceil(this.height*q);return d=this.getTileWidth(a),e=this.getTileHeight(a),f=Math.ceil(d/q),g=Math.ceil(e/q),n=this["@context"].indexOf("/1.0/context.json")>-1||this["@context"].indexOf("/1.1/context.json")>-1||this["@context"].indexOf("/1/context.json")>-1?"native.jpg":"default.jpg",d>r&&e>s?(m=r+",",h="full"):(i=b*f,j=c*g,k=Math.min(f,this.width-i),l=Math.min(g,this.height-j),m=Math.ceil(k*q)+",",h=[i,j,k,l].join(",")),o=[this["@id"],h,m,p,n].join("/")}})}(OpenSeadragon),function(a){a.OsmTileSource=function(b,c,d,e,f){var g;g=a.isPlainObject(b)?b:{width:arguments[0],height:arguments[1],tileSize:arguments[2],tileOverlap:arguments[3],tilesUrl:arguments[4]},g.width&&g.height||(g.width=65572864,g.height=65572864),g.tileSize||(g.tileSize=256,g.tileOverlap=0),g.tilesUrl||(g.tilesUrl="http://tile.openstreetmap.org/"),g.minLevel=8,a.TileSource.apply(this,[g])},a.extend(a.OsmTileSource.prototype,a.TileSource.prototype,{supports:function(a,b){return a.type&&"openstreetmaps"==a.type},configure:function(a,b){return a},getTileUrl:function(a,b,c){return this.tilesUrl+(a-8)+"/"+b+"/"+c+".png"}})}(OpenSeadragon),function(a){a.TmsTileSource=function(b,c,d,e,f){var g;g=a.isPlainObject(b)?b:{width:arguments[0],height:arguments[1],tileSize:arguments[2],tileOverlap:arguments[3],tilesUrl:arguments[4]};var h,i=256*Math.ceil(g.width/256),j=256*Math.ceil(g.height/256);h=i>j?i/256:j/256,g.maxLevel=Math.ceil(Math.log(h)/Math.log(2))-1,g.tileSize=256,g.width=i,g.height=j,a.TileSource.apply(this,[g])},a.extend(a.TmsTileSource.prototype,a.TileSource.prototype,{supports:function(a,b){return a.type&&"tiledmapservice"==a.type},configure:function(a,b){return a},getTileUrl:function(a,b,c){var d=this.getNumTiles(a).y-1;return this.tilesUrl+a+"/"+b+"/"+(d-c)+".png"}})}(OpenSeadragon),function(a){function b(b){var c,d,e=[];for(d=0;d");return e.sort(function(a,b){return a.height-b.height})}function c(b,c){if(!c||!c.documentElement)throw new Error(a.getString("Errors.Xml"));var e,f,g=c.documentElement,h=g.tagName,i=null,j=[];if("image"==h)try{for(i={type:g.getAttribute("type"),levels:[]},j=g.getElementsByTagName("level"),f=0;f0?(e=d.levels[d.levels.length-1].width,f=d.levels[d.levels.length-1].height):(e=0,f=0,a.console.error("No supported image formats found")),a.extend(!0,d,{width:e,height:f,tileSize:Math.max(f,e),tileOverlap:0,minLevel:0,maxLevel:d.levels.length>0?d.levels.length-1:0}),a.TileSource.apply(this,[d]),this.levels=d.levels},a.extend(a.LegacyTileSource.prototype,a.TileSource.prototype,{supports:function(a,b){return a.type&&"legacy-image-pyramid"==a.type||a.documentElement&&"legacy-image-pyramid"==a.documentElement.getAttribute("type")},configure:function(b,e){var f;return f=a.isPlainObject(b)?d(this,b):c(this,b)},getLevelScale:function(a){var b=NaN;return this.levels.length>0&&a>=this.minLevel&&a<=this.maxLevel&&(b=this.levels[a].width/this.levels[this.maxLevel].width),b},getNumTiles:function(b){var c=this.getLevelScale(b);return c?new a.Point(1,1):new a.Point(0,0)},getTileAtPoint:function(b,c){return new a.Point(0,0)},getTileUrl:function(a,b,c){var d=null;return this.levels.length>0&&a>=this.minLevel&&a<=this.maxLevel&&(d=this.levels[a].url),d}})}(OpenSeadragon),function(a){a.ImageTileSource=function(b){b=a.extend({buildPyramid:!0,crossOriginPolicy:!1,ajaxWithCredentials:!1,useCanvas:!0},b),a.TileSource.apply(this,[b])},a.extend(a.ImageTileSource.prototype,a.TileSource.prototype,{supports:function(a,b){return a.type&&"image"===a.type},configure:function(a,b){return a},getImageInfo:function(b){var c=this._image=new Image,d=this;this.crossOriginPolicy&&(c.crossOrigin=this.crossOriginPolicy),this.ajaxWithCredentials&&(c.useCredentials=this.ajaxWithCredentials),a.addEvent(c,"load",function(){d.width=c.naturalWidth,d.height=c.naturalHeight,d.aspectRatio=d.width/d.height,d.dimensions=new a.Point(d.width,d.height),d._tileWidth=d.width,d._tileHeight=d.height,d.tileOverlap=0,d.minLevel=0,d.levels=d._buildLevels(),d.maxLevel=d.levels.length-1,d.ready=!0,d.raiseEvent("ready",{tileSource:d})}),a.addEvent(c,"error",function(){d.raiseEvent("open-failed",{message:"Error loading image at "+b,source:b})}),c.src=b},getLevelScale:function(a){var b=NaN;return a>=this.minLevel&&a<=this.maxLevel&&(b=this.levels[a].width/this.levels[this.maxLevel].width),b},getNumTiles:function(b){var c=this.getLevelScale(b);return c?new a.Point(1,1):new a.Point(0,0)},getTileAtPoint:function(b,c){return new a.Point(0,0)},getTileUrl:function(a,b,c){var d=null;return a>=this.minLevel&&a<=this.maxLevel&&(d=this.levels[a].url),d},getContext2D:function(a,b,c){var d=null;return a>=this.minLevel&&a<=this.maxLevel&&(d=this.levels[a].context2D),d},_buildLevels:function(){var b=[{url:this._image.src,width:this._image.naturalWidth,height:this._image.naturalHeight}];if(!this.buildPyramid||!a.supportsCanvas||!this.useCanvas)return delete this._image,b;var c=this._image.naturalWidth,d=this._image.naturalHeight,e=document.createElement("canvas"),f=e.getContext("2d");if(e.width=c,e.height=d,f.drawImage(this._image,0,0,c,d),b[0].context2D=f,delete this._image,a.isCanvasTainted(e))return b;for(;c>=2&&d>=2;){c=Math.floor(c/2),d=Math.floor(d/2);var g=document.createElement("canvas"),h=g.getContext("2d");g.width=c,g.height=d,h.drawImage(e,0,0,c,d),b.splice(0,0,{context2D:h,width:c,height:d}),e=g,f=h}return b}})}(OpenSeadragon),function(a){a.TileSourceCollection=function(b,c,d,e){a.console.error("TileSourceCollection is deprecated; use World instead")}}(OpenSeadragon),function(a){function b(b){a.requestAnimationFrame(function(){c(b)})}function c(c){var d,e,f;c.shouldFade&&(d=a.now(),e=d-c.fadeBeginTime,f=1-e/c.fadeLength,f=Math.min(1,f),f=Math.max(0,f),c.imgGroup&&a.setElementOpacity(c.imgGroup,f,!0),f>0&&b(c))}function d(c){c.shouldFade=!0,c.fadeBeginTime=a.now()+c.fadeDelay,window.setTimeout(function(){b(c)},c.fadeDelay)}function e(b){b.shouldFade=!1,b.imgGroup&&a.setElementOpacity(b.imgGroup,1,!0)}function f(b,c){b.element.disabled||(c>=a.ButtonState.GROUP&&b.currentState==a.ButtonState.REST&&(e(b),b.currentState=a.ButtonState.GROUP),c>=a.ButtonState.HOVER&&b.currentState==a.ButtonState.GROUP&&(b.imgHover&&(b.imgHover.style.visibility=""),b.currentState=a.ButtonState.HOVER),c>=a.ButtonState.DOWN&&b.currentState==a.ButtonState.HOVER&&(b.imgDown&&(b.imgDown.style.visibility=""),b.currentState=a.ButtonState.DOWN))}function g(b,c){b.element.disabled||(c<=a.ButtonState.HOVER&&b.currentState==a.ButtonState.DOWN&&(b.imgDown&&(b.imgDown.style.visibility="hidden"),b.currentState=a.ButtonState.HOVER),c<=a.ButtonState.GROUP&&b.currentState==a.ButtonState.HOVER&&(b.imgHover&&(b.imgHover.style.visibility="hidden"),b.currentState=a.ButtonState.GROUP),c<=a.ButtonState.REST&&b.currentState==a.ButtonState.GROUP&&(d(b),b.currentState=a.ButtonState.REST))}a.ButtonState={REST:0,GROUP:1,HOVER:2,DOWN:3},a.Button=function(b){var c=this;a.EventSource.call(this),a.extend(!0,this,{tooltip:null,srcRest:null,srcGroup:null,srcHover:null,srcDown:null,clickTimeThreshold:a.DEFAULT_SETTINGS.clickTimeThreshold,clickDistThreshold:a.DEFAULT_SETTINGS.clickDistThreshold,fadeDelay:0,fadeLength:2e3,onPress:null,onRelease:null,onClick:null,onEnter:null,onExit:null,onFocus:null,onBlur:null},b),this.element=b.element||a.makeNeutralElement("div"),b.element||(this.imgRest=a.makeTransparentImage(this.srcRest),this.imgGroup=a.makeTransparentImage(this.srcGroup),this.imgHover=a.makeTransparentImage(this.srcHover),this.imgDown=a.makeTransparentImage(this.srcDown),this.imgRest.alt=this.imgGroup.alt=this.imgHover.alt=this.imgDown.alt=this.tooltip,this.element.style.position="relative",a.setElementTouchActionNone(this.element),this.imgGroup.style.position=this.imgHover.style.position=this.imgDown.style.position="absolute",this.imgGroup.style.top=this.imgHover.style.top=this.imgDown.style.top="0px",this.imgGroup.style.left=this.imgHover.style.left=this.imgDown.style.left="0px",this.imgHover.style.visibility=this.imgDown.style.visibility="hidden",a.Browser.vendor==a.BROWSERS.FIREFOX&&a.Browser.version<3&&(this.imgGroup.style.top=this.imgHover.style.top=this.imgDown.style.top=""),this.element.appendChild(this.imgRest),this.element.appendChild(this.imgGroup),this.element.appendChild(this.imgHover),this.element.appendChild(this.imgDown)),this.addHandler("press",this.onPress),this.addHandler("release",this.onRelease),this.addHandler("click",this.onClick),this.addHandler("enter",this.onEnter),this.addHandler("exit",this.onExit),this.addHandler("focus",this.onFocus),this.addHandler("blur",this.onBlur),this.currentState=a.ButtonState.GROUP,this.fadeBeginTime=null,this.shouldFade=!1,this.element.style.display="inline-block",this.element.style.position="relative",this.element.title=this.tooltip,this.tracker=new a.MouseTracker({element:this.element,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,enterHandler:function(b){b.insideElementPressed?(f(c,a.ButtonState.DOWN),c.raiseEvent("enter",{originalEvent:b.originalEvent})):b.buttonDownAny||f(c,a.ButtonState.HOVER)},focusHandler:function(a){this.enterHandler(a),c.raiseEvent("focus",{originalEvent:a.originalEvent})},exitHandler:function(b){g(c,a.ButtonState.GROUP),b.insideElementPressed&&c.raiseEvent("exit",{originalEvent:b.originalEvent})},blurHandler:function(a){this.exitHandler(a),c.raiseEvent("blur",{originalEvent:a.originalEvent})},pressHandler:function(b){f(c,a.ButtonState.DOWN),c.raiseEvent("press",{originalEvent:b.originalEvent})},releaseHandler:function(b){b.insideElementPressed&&b.insideElementReleased?(g(c,a.ButtonState.HOVER),c.raiseEvent("release",{originalEvent:b.originalEvent})):b.insideElementPressed?g(c,a.ButtonState.GROUP):f(c,a.ButtonState.HOVER)},clickHandler:function(a){a.quick&&c.raiseEvent("click",{originalEvent:a.originalEvent})},keyHandler:function(a){return 13===a.keyCode?(c.raiseEvent("click",{originalEvent:a.originalEvent}),c.raiseEvent("release",{originalEvent:a.originalEvent}),!1):!0}}),g(this,a.ButtonState.REST)},a.extend(a.Button.prototype,a.EventSource.prototype,{notifyGroupEnter:function(){f(this,a.ButtonState.GROUP)},notifyGroupExit:function(){g(this,a.ButtonState.REST)},disable:function(){this.notifyGroupExit(),this.element.disabled=!0,a.setElementOpacity(this.element,.2,!0)},enable:function(){this.element.disabled=!1,a.setElementOpacity(this.element,1,!0),this.notifyGroupEnter()}})}(OpenSeadragon),function(a){a.ButtonGroup=function(b){a.extend(!0,this,{buttons:[],clickTimeThreshold:a.DEFAULT_SETTINGS.clickTimeThreshold,clickDistThreshold:a.DEFAULT_SETTINGS.clickDistThreshold,labelText:""},b);var c,d=this.buttons.concat([]),e=this;if(this.element=b.element||a.makeNeutralElement("div"),!b.group)for(this.label=a.makeNeutralElement("label"),this.element.style.display="inline-block",this.element.appendChild(this.label),c=0;c0?c>-(f-h.x)&&(this.element.style.marginLeft=c+2*b.delta.x+"px",d(this,h.x,c+2*b.delta.x)):-b.delta.x<0&&0>c&&(this.element.style.marginLeft=c+2*b.delta.x+"px",d(this,h.x,c+2*b.delta.x)):-b.delta.y>0?e>-(g-h.y)&&(this.element.style.marginTop=e+2*b.delta.y+"px",d(this,h.y,e+2*b.delta.y)):-b.delta.y<0&&0>e&&(this.element.style.marginTop=e+2*b.delta.y+"px",d(this,h.y,e+2*b.delta.y))),!1}function c(b){var c=Number(this.element.style.marginLeft.replace("px","")),e=Number(this.element.style.marginTop.replace("px","")),f=Number(this.element.style.width.replace("px","")),g=Number(this.element.style.height.replace("px","")),h=a.getElementSize(this.viewer.canvas);return this.element&&("horizontal"==this.scroll?b.scroll>0?c>-(f-h.x)&&(this.element.style.marginLeft=c-60*b.scroll+"px",d(this,h.x,c-60*b.scroll)):b.scroll<0&&0>c&&(this.element.style.marginLeft=c-60*b.scroll+"px",d(this,h.x,c-60*b.scroll)):b.scroll<0?e>h.y-g&&(this.element.style.marginTop=e+60*b.scroll+"px",d(this,h.y,e+60*b.scroll)):b.scroll>0&&0>e&&(this.element.style.marginTop=e+60*b.scroll+"px",d(this,h.y,e+60*b.scroll))),!1}function d(b,c,d){var e,f,g,h,i,j,k;for(e="horizontal"==b.scroll?b.panelWidth:b.panelHeight,f=Math.ceil(c/e)+5,g=Math.ceil((Math.abs(d)+c)/e)+1,f=g-f,f=0>f?0:f,j=f;g>j&&jj+g.x-this.panelWidth?(c=Math.min(c,h-g.x),this.element.style.marginLeft=-c+"px",d(this,g.x,-c)):j>c&&(c=Math.max(0,c-g.x/2),this.element.style.marginLeft=-c+"px",d(this,g.x,-c))):(c=Number(b)*(this.panelHeight+3),c>k+g.y-this.panelHeight?(c=Math.min(c,i-g.y),this.element.style.marginTop=-c+"px",d(this,g.y,-c)):k>c&&(c=Math.max(0,c-g.y/2),this.element.style.marginTop=-c+"px",d(this,g.y,-c))),this.currentPage=b,a.getElement(f.id+"-displayregion").focus(),e.call(this,{eventSource:this.innerTracker}))},update:function(){return i[this.id].animating?(a.console.log("image reference strip update"),!0):!1},destroy:function(){this.element&&this.element.parentNode.removeChild(this.element)}})}(OpenSeadragon),function(a){a.DisplayRect=function(b,c,d,e,f,g){a.Rect.apply(this,[b,c,d,e]),this.minLevel=f,this.maxLevel=g},a.extend(a.DisplayRect.prototype,a.Rect.prototype)}(OpenSeadragon),function(a){function b(a,b){return(1-Math.exp(a*-b))/(1-Math.exp(-a))}a.Spring=function(b){var c=arguments;"object"!=typeof b&&(b={initial:c.length&&"number"==typeof c[0]?c[0]:void 0,springStiffness:c.length>1?c[1].springStiffness:5,animationTime:c.length>1?c[1].animationTime:1.5}),a.console.assert("number"==typeof b.springStiffness&&0!==b.springStiffness,"[OpenSeadragon.Spring] options.springStiffness must be a non-zero number"),a.console.assert("number"==typeof b.animationTime&&0!==b.springStiffness,"[OpenSeadragon.Spring] options.animationTime must be a non-zero number"),b.exponential&&(this._exponential=!0,delete b.exponential),a.extend(!0,this,b),this.current={value:"number"==typeof this.initial?this.initial:this._exponential?0:1,time:a.now()},a.console.assert(!this._exponential||0!==this.current.value,"[OpenSeadragon.Spring] value must be non-zero for exponential springs"),this.start={value:this.current.value,time:this.current.time},this.target={value:this.current.value,time:this.current.time},this._exponential&&(this.start._logValue=Math.log(this.start.value),this.target._logValue=Math.log(this.target.value),this.current._logValue=Math.log(this.current.value))},a.Spring.prototype={resetTo:function(b){a.console.assert(!this._exponential||0!==b,"[OpenSeadragon.Spring.resetTo] target must be non-zero for exponential springs"),this.start.value=this.target.value=this.current.value=b,this.start.time=this.target.time=this.current.time=a.now(),this._exponential&&(this.start._logValue=Math.log(this.start.value),this.target._logValue=Math.log(this.target.value),this.current._logValue=Math.log(this.current.value))},springTo:function(b){a.console.assert(!this._exponential||0!==b,"[OpenSeadragon.Spring.springTo] target must be non-zero for exponential springs"),this.start.value=this.current.value,this.start.time=this.current.time,this.target.value=b,this.target.time=this.start.time+1e3*this.animationTime,this._exponential&&(this.start._logValue=Math.log(this.start.value),this.target._logValue=Math.log(this.target.value))},shiftBy:function(b){this.start.value+=b,this.target.value+=b,this._exponential&&(a.console.assert(0!==this.target.value&&0!==this.start.value,"[OpenSeadragon.Spring.shiftBy] spring value must be non-zero for exponential springs"),this.start._logValue=Math.log(this.start.value),this.target._logValue=Math.log(this.target.value))},setExponential:function(b){this._exponential=b,this._exponential&&(a.console.assert(0!==this.current.value&&0!==this.target.value&&0!==this.start.value,"[OpenSeadragon.Spring.setExponential] spring value must be non-zero for exponential springs"),this.start._logValue=Math.log(this.start.value),this.target._logValue=Math.log(this.target.value),this.current._logValue=Math.log(this.current.value))},update:function(){this.current.time=a.now();var c,d;this._exponential?(c=this.start._logValue,d=this.target._logValue):(c=this.start.value,d=this.target.value);var e=this.current.time>=this.target.time?d:c+(d-c)*b(this.springStiffness,(this.current.time-this.start.time)/(this.target.time-this.start.time));this._exponential?this.current.value=Math.exp(e):this.current.value=e}}}(OpenSeadragon),function(a){function b(b){a.extend(!0,this,{timeout:a.DEFAULT_SETTINGS.timeout,jobId:null},b),this.image=null}function c(a,b,c){var d;a.jobsInProgress--,(!a.jobLimit||a.jobsInProgress0&&(d=a.jobQueue.shift(),d.start(),a.jobsInProgress++),c(b.image,b.errorMsg)}b.prototype={errorMsg:null,start:function(){var a=this;this.image=new Image,this.crossOriginPolicy!==!1&&(this.image.crossOrigin=this.crossOriginPolicy),this.image.onload=function(){a.finish(!0)},this.image.onabort=this.image.onerror=function(){a.errorMsg="Image load aborted",a.finish(!1)},this.jobId=window.setTimeout(function(){a.errorMsg="Image load exceeded timeout",a.finish(!1)},this.timeout),this.image.src=this.src},finish:function(a){this.image.onload=this.image.onerror=this.image.onabort=null,a||(this.image=null),this.jobId&&window.clearTimeout(this.jobId),this.callback(this)}},a.ImageLoader=function(b){a.extend(!0,this,{jobLimit:a.DEFAULT_SETTINGS.imageLoaderLimit,jobQueue:[],jobsInProgress:0},b)},a.ImageLoader.prototype={addJob:function(a){var d=this,e=function(b){c(d,b,a.callback)},f={src:a.src,crossOriginPolicy:a.crossOriginPolicy,callback:e,abort:a.abort},g=new b(f);!this.jobLimit||this.jobsInProgressc&&(c=e)}return c},needsUpdate:function(){return a.console.error("[Drawer.needsUpdate] this function is deprecated. Use World.needsDraw instead."),this.viewer.world.needsDraw()},numTilesLoaded:function(){return a.console.error("[Drawer.numTilesLoaded] this function is deprecated. Use TileCache.numTilesLoaded instead."),this.viewer.tileCache.numTilesLoaded()},reset:function(){return a.console.error("[Drawer.reset] this function is deprecated. Use World.resetItems instead."),this.viewer.world.resetItems(),this},update:function(){return a.console.error("[Drawer.update] this function is deprecated. Use Drawer.clear and World.draw instead."),this.clear(),this.viewer.world.draw(),this},canRotate:function(){return this.useCanvas},destroy:function(){this.canvas.width=1,this.canvas.height=1,this.sketchCanvas=null,this.sketchContext=null},clear:function(){if(this.canvas.innerHTML="",this.useCanvas){var a=this._calculateCanvasSize();(this.canvas.width!=a.x||this.canvas.height!=a.y)&&(this.canvas.width=a.x,this.canvas.height=a.y,null!==this.sketchCanvas&&(this.sketchCanvas.width=this.canvas.width,this.sketchCanvas.height=this.canvas.height)),this._clear()}},_clear:function(a){if(this.useCanvas){var b=this._getContext(a),c=b.canvas;b.clearRect(0,0,c.width,c.height)}},viewportToDrawerRectangle:function(b){var c=this.viewport.pixelFromPoint(b.getTopLeft(),!0),d=this.viewport.deltaPixelsFromPoints(b.getSize(),!0);return new a.Rect(c.x*a.pixelDensityRatio,c.y*a.pixelDensityRatio,d.x*a.pixelDensityRatio,d.y*a.pixelDensityRatio)},drawTile:function(b,c,d){if(a.console.assert(b,"[Drawer.drawTile] tile is required"),a.console.assert(c,"[Drawer.drawTile] drawingHandler is required"),this.useCanvas){var e=this._getContext(d);0!==this.viewport.degrees?(this._offsetForRotation(b,this.viewport.degrees,d),b.drawCanvas(e,c),this._restoreRotationChanges(b,d)):b.drawCanvas(e,c)}else b.drawHTML(this.canvas)},_getContext:function(a){var b=this.context;return a&&(null===this.sketchCanvas&&(this.sketchCanvas=document.createElement("canvas"),this.sketchCanvas.width=this.canvas.width,this.sketchCanvas.height=this.canvas.height,this.sketchContext=this.sketchCanvas.getContext("2d")),b=this.sketchContext),b},saveContext:function(a){this.useCanvas&&this._getContext(a).save()},restoreContext:function(a){this.useCanvas&&this._getContext(a).restore()},setClip:function(a,b){if(this.useCanvas){var c=this._getContext(b);c.beginPath(),c.rect(a.x,a.y,a.width,a.height),c.clip()}},drawRectangle:function(a,b,c){if(this.useCanvas){var d=this._getContext(c);d.save(),d.fillStyle=b,d.fillRect(a.x,a.y,a.width,a.height),d.restore()}},blendSketch:function(a){this.useCanvas&&this.sketchCanvas&&(this.context.save(),this.context.globalAlpha=a,this.context.drawImage(this.sketchCanvas,0,0),this.context.restore())},drawDebugInfo:function(b,c,d){if(this.useCanvas){var e=this.context;e.save(),e.lineWidth=2*a.pixelDensityRatio,e.font="small-caps bold "+13*a.pixelDensityRatio+"px arial",e.strokeStyle=this.debugGridColor,e.fillStyle=this.debugGridColor,0!==this.viewport.degrees&&this._offsetForRotation(b,this.viewport.degrees),e.strokeRect(b.position.x*a.pixelDensityRatio,b.position.y*a.pixelDensityRatio,b.size.x*a.pixelDensityRatio,b.size.y*a.pixelDensityRatio);var f=(b.position.x+b.size.x/2)*a.pixelDensityRatio,g=(b.position.y+b.size.y/2)*a.pixelDensityRatio;e.translate(f,g),e.rotate(Math.PI/180*-this.viewport.degrees),e.translate(-f,-g),0===b.x&&0===b.y&&(e.fillText("Zoom: "+this.viewport.getZoom(),b.position.x*a.pixelDensityRatio,(b.position.y-30)*a.pixelDensityRatio),e.fillText("Pan: "+this.viewport.getBounds().toString(),b.position.x*a.pixelDensityRatio,(b.position.y-20)*a.pixelDensityRatio)),e.fillText("Level: "+b.level,(b.position.x+10)*a.pixelDensityRatio,(b.position.y+20)*a.pixelDensityRatio),e.fillText("Column: "+b.x,(b.position.x+10)*a.pixelDensityRatio,(b.position.y+30)*a.pixelDensityRatio),e.fillText("Row: "+b.y,(b.position.x+10)*a.pixelDensityRatio,(b.position.y+40)*a.pixelDensityRatio),e.fillText("Order: "+d+" of "+c,(b.position.x+10)*a.pixelDensityRatio,(b.position.y+50)*a.pixelDensityRatio),e.fillText("Size: "+b.size.toString(),(b.position.x+10)*a.pixelDensityRatio,(b.position.y+60)*a.pixelDensityRatio),e.fillText("Position: "+b.position.toString(),(b.position.x+10)*a.pixelDensityRatio,(b.position.y+70)*a.pixelDensityRatio),0!==this.viewport.degrees&&this._restoreRotationChanges(b),e.restore()}},debugRect:function(b){if(this.useCanvas){var c=this.context;c.save(),c.lineWidth=2*a.pixelDensityRatio,c.strokeStyle=this.debugGridColor,c.fillStyle=this.debugGridColor,c.strokeRect(b.x*a.pixelDensityRatio,b.y*a.pixelDensityRatio,b.width*a.pixelDensityRatio,b.height*a.pixelDensityRatio),c.restore()}},_offsetForRotation:function(a,b,c){var d=this.canvas.width/2,e=this.canvas.height/2,f=this._getContext(c);f.save(),f.translate(d,e),f.rotate(Math.PI/180*b),f.translate(-d,-e)},_restoreRotationChanges:function(a,b){var c=this._getContext(b);c.restore()},_calculateCanvasSize:function(){var b=a.pixelDensityRatio,c=this.viewport.getContainerSize();return{x:c.x*b,y:c.y*b}}}}(OpenSeadragon),function(a){a.Viewport=function(b){var c=arguments;c.length&&c[0]instanceof a.Point&&(b={containerSize:c[0],contentSize:c[1],config:c[2]}),b.config&&(a.extend(!0,b,b.config),delete b.config),this._margins=a.extend({left:0,top:0,right:0,bottom:0},b.margins||{}),delete b.margins,a.extend(!0,this,{containerSize:null,contentSize:null,zoomPoint:null,viewer:null,springStiffness:a.DEFAULT_SETTINGS.springStiffness,animationTime:a.DEFAULT_SETTINGS.animationTime,minZoomImageRatio:a.DEFAULT_SETTINGS.minZoomImageRatio,maxZoomPixelRatio:a.DEFAULT_SETTINGS.maxZoomPixelRatio,visibilityRatio:a.DEFAULT_SETTINGS.visibilityRatio,wrapHorizontal:a.DEFAULT_SETTINGS.wrapHorizontal,wrapVertical:a.DEFAULT_SETTINGS.wrapVertical,defaultZoomLevel:a.DEFAULT_SETTINGS.defaultZoomLevel,minZoomLevel:a.DEFAULT_SETTINGS.minZoomLevel,maxZoomLevel:a.DEFAULT_SETTINGS.maxZoomLevel,degrees:a.DEFAULT_SETTINGS.degrees,homeFillsViewer:a.DEFAULT_SETTINGS.homeFillsViewer},b),this._updateContainerInnerSize(),this.centerSpringX=new a.Spring({initial:0,springStiffness:this.springStiffness,animationTime:this.animationTime}),this.centerSpringY=new a.Spring({initial:0,springStiffness:this.springStiffness,animationTime:this.animationTime}),this.zoomSpring=new a.Spring({exponential:!0,initial:1,springStiffness:this.springStiffness,animationTime:this.animationTime}),this._oldCenterX=this.centerSpringX.current.value,this._oldCenterY=this.centerSpringY.current.value,this._oldZoom=this.zoomSpring.current.value,this.contentSize?this.resetContentSize(this.contentSize):this.setHomeBounds(new a.Rect(0,0,1,1),1),this.goHome(!0),this.update()},a.Viewport.prototype={resetContentSize:function(b){return a.console.assert(b,"[Viewport.resetContentSize] contentSize is required"),a.console.assert(b instanceof a.Point,"[Viewport.resetContentSize] contentSize must be an OpenSeadragon.Point"),a.console.assert(b.x>0,"[Viewport.resetContentSize] contentSize.x must be greater than 0"),a.console.assert(b.y>0,"[Viewport.resetContentSize] contentSize.y must be greater than 0"),this.setHomeBounds(new a.Rect(0,0,1,b.y/b.x),b.x),this},setHomeBounds:function(b,c){a.console.assert(b,"[Viewport.setHomeBounds] bounds is required"),a.console.assert(b instanceof a.Rect,"[Viewport.setHomeBounds] bounds must be an OpenSeadragon.Rect"),a.console.assert(b.width>0,"[Viewport.setHomeBounds] bounds.width must be greater than 0"),a.console.assert(b.height>0,"[Viewport.setHomeBounds] bounds.height must be greater than 0"),this.homeBounds=b.clone(),this.contentSize=this.homeBounds.getSize().times(c),this.contentAspectX=this.contentSize.x/this.contentSize.y,this.contentAspectY=this.contentSize.y/this.contentSize.x,this.viewer&&this.viewer.raiseEvent("reset-size",{contentSize:this.contentSize.clone(),contentFactor:c,homeBounds:this.homeBounds.clone()})},getHomeZoom:function(){if(this.defaultZoomLevel)return this.defaultZoomLevel;var a,b=this.contentAspectX/this.getAspectRatio();return a=this.homeFillsViewer?b>=1?b:1:b>=1?1:b,a/this.homeBounds.width},getHomeBounds:function(){var b=this.homeBounds.getCenter(),c=1/this.getHomeZoom(),d=c/this.getAspectRatio();return new a.Rect(b.x-c/2,b.y-d/2,c,d)},goHome:function(a){return this.viewer&&this.viewer.raiseEvent("home",{immediately:a}),this.fitBounds(this.getHomeBounds(),a)},getMinZoom:function(){var a=this.getHomeZoom(),b=this.minZoomLevel?this.minZoomLevel:this.minZoomImageRatio*a;return b},getMaxZoom:function(){var a=this.maxZoomLevel;return a||(a=this.contentSize.x*this.maxZoomPixelRatio/this._containerInnerSize.x,a/=this.homeBounds.width),Math.max(a,this.getHomeZoom())},getAspectRatio:function(){return this._containerInnerSize.x/this._containerInnerSize.y},getContainerSize:function(){return new a.Point(this.containerSize.x,this.containerSize.y)},getMargins:function(){return a.extend({},this._margins)},setMargins:function(b){a.console.assert("object"===a.type(b),"[Viewport.setMargins] margins must be an object"),this._margins=a.extend({left:0,top:0,right:0,bottom:0},b),this._updateContainerInnerSize(),this.viewer.forceRedraw()},getBounds:function(b){var c=this.getCenter(b),d=1/this.getZoom(b),e=d/this.getAspectRatio();return new a.Rect(c.x-d/2,c.y-e/2,d,e)},getBoundsWithMargins:function(a){var b=this.getBounds(a),c=this._containerInnerSize.x*this.getZoom(a);return b.x-=this._margins.left/c,b.y-=this._margins.top/c,b.width+=(this._margins.left+this._margins.right)/c,b.height+=(this._margins.top+this._margins.bottom)/c,b},getCenter:function(b){var c,d,e,f,g,h,i,j,k=new a.Point(this.centerSpringX.current.value,this.centerSpringY.current.value),l=new a.Point(this.centerSpringX.target.value,this.centerSpringY.target.value);return b?k:this.zoomPoint?(c=this.pixelFromPoint(this.zoomPoint,!0),d=this.getZoom(),e=1/d,f=e/this.getAspectRatio(),g=new a.Rect(k.x-e/2,k.y-f/2,e,f),h=this._pixelFromPoint(this.zoomPoint,g),i=h.minus(c),j=i.divide(this._containerInnerSize.x*d),l.plus(j)):l},getZoom:function(a){return a?this.zoomSpring.current.value:this.zoomSpring.target.value},_applyBoundaryConstraints:function(b,c){var d=0,e=0,f=new a.Rect(b.x,b.y,b.width,b.height),g=this.visibilityRatio*f.width,h=this.visibilityRatio*f.height;if(this.wrapHorizontal);else{var i=f.x+(f.width-g);this.homeBounds.x>i&&(d=this.homeBounds.x-i);var j=this.homeBounds.x+this.homeBounds.width,k=f.x+g;if(k>j){var l=j-k;d=d?(d+l)/2:l}}if(this.wrapVertical);else{var m=f.y+(f.height-h);this.homeBounds.y>m&&(e=this.homeBounds.y-m);var n=this.homeBounds.y+this.homeBounds.height,o=f.y+h;if(o>n){var p=n-o;e=e?(e+p)/2:p}}return(d||e)&&(f.x+=d,f.y+=e),this.viewer&&this.viewer.raiseEvent("constrain",{immediately:c}),f},applyConstraints:function(a){var b,c,d=this.getZoom(),e=Math.max(Math.min(d,this.getMaxZoom()),this.getMinZoom());return d!=e&&this.zoomTo(e,this.zoomPoint,a),b=this.getBounds(),c=this._applyBoundaryConstraints(b,a),(b.x!==c.x||b.y!==c.y||a)&&this.fitBounds(c,a),this},ensureVisible:function(a){return this.applyConstraints(a)},_fitBounds:function(b,c){c=c||{};var d,e,f,g,h,i,j=c.immediately||!1,k=c.constraints||!1,l=this.getAspectRatio(),m=b.getCenter(),n=new a.Rect(b.x,b.y,b.width,b.height);return n.getAspectRatio()>=l?(n.height=b.width/l,n.y=m.y-n.height/2):(n.width=b.height*l, -n.x=m.x-n.width/2),k&&(h=n.getAspectRatio()),this.panTo(this.getCenter(!0),!0),this.zoomTo(this.getZoom(!0),null,!0),d=this.getBounds(),e=this.getZoom(),f=1/n.width,k&&(i=Math.max(Math.min(f,this.getMaxZoom()),this.getMinZoom()),f!==i&&(f=i,n.width=1/f,n.x=m.x-n.width/2,n.height=n.width/h,n.y=m.y-n.height/2),n=this._applyBoundaryConstraints(n,j),m=n.getCenter()),j?(this.panTo(m,!0),this.zoomTo(f,null,!0)):Math.abs(f-e)<1e-8||Math.abs(n.width-d.width)<1e-8?this.panTo(m,j):(g=d.getTopLeft().times(this._containerInnerSize.x/d.width).minus(n.getTopLeft().times(this._containerInnerSize.x/n.width)).divide(this._containerInnerSize.x/d.width-this._containerInnerSize.x/n.width),this.zoomTo(f,g,j))},fitBounds:function(a,b){return this._fitBounds(a,{immediately:b,constraints:!1})},fitBoundsWithConstraints:function(a,b){return this._fitBounds(a,{immediately:b,constraints:!0})},fitVertically:function(b){var c=new a.Rect(this.homeBounds.x+this.homeBounds.width/2,this.homeBounds.y,0,this.homeBounds.height);return this.fitBounds(c,b)},fitHorizontally:function(b){var c=new a.Rect(this.homeBounds.x,this.homeBounds.y+this.homeBounds.height/2,this.homeBounds.width,0);return this.fitBounds(c,b)},panBy:function(b,c){var d=new a.Point(this.centerSpringX.target.value,this.centerSpringY.target.value);return b=b.rotate(-this.degrees,new a.Point(0,0)),this.panTo(d.plus(b),c)},panTo:function(a,b){return b?(this.centerSpringX.resetTo(a.x),this.centerSpringY.resetTo(a.y)):(this.centerSpringX.springTo(a.x),this.centerSpringY.springTo(a.y)),this.viewer&&this.viewer.raiseEvent("pan",{center:a,immediately:b}),this},zoomBy:function(b,c,d){return c instanceof a.Point&&!isNaN(c.x)&&!isNaN(c.y)&&(c=c.rotate(-this.degrees,new a.Point(this.centerSpringX.target.value,this.centerSpringY.target.value))),this.zoomTo(this.zoomSpring.target.value*b,c,d)},zoomTo:function(b,c,d){return this.zoomPoint=c instanceof a.Point&&!isNaN(c.x)&&!isNaN(c.y)?c:null,d?this.zoomSpring.resetTo(b):this.zoomSpring.springTo(b),this.viewer&&this.viewer.raiseEvent("zoom",{zoom:b,refPoint:c,immediately:d}),this},setRotation:function(a){return this.viewer&&this.viewer.drawer.canRotate()?(a=(a+360)%360,this.degrees=a,this.viewer.forceRedraw(),null!==this.viewer&&this.viewer.raiseEvent("rotate",{degrees:a}),this):this},getRotation:function(){return this.degrees},resize:function(a,b){var c,d=this.getBounds(),e=d;return this.containerSize.x=a.x,this.containerSize.y=a.y,this._updateContainerInnerSize(),b&&(c=a.x/this.containerSize.x,e.width=d.width*c,e.height=e.width/this.getAspectRatio()),this.viewer&&this.viewer.raiseEvent("resize",{newContainerSize:a,maintain:b}),this.fitBounds(e,!0)},_updateContainerInnerSize:function(){this._containerInnerSize=new a.Point(Math.max(1,this.containerSize.x-(this._margins.left+this._margins.right)),Math.max(1,this.containerSize.y-(this._margins.top+this._margins.bottom)))},update:function(){var a,b,c,d;this.zoomPoint&&(a=this.pixelFromPoint(this.zoomPoint,!0)),this.zoomSpring.update(),this.zoomPoint&&this.zoomSpring.current.value!=this._oldZoom?(b=this.pixelFromPoint(this.zoomPoint,!0),c=b.minus(a),d=this.deltaPointsFromPixels(c,!0),this.centerSpringX.shiftBy(d.x),this.centerSpringY.shiftBy(d.y)):this.zoomPoint=null,this.centerSpringX.update(),this.centerSpringY.update();var e=this.centerSpringX.current.value!=this._oldCenterX||this.centerSpringY.current.value!=this._oldCenterY||this.zoomSpring.current.value!=this._oldZoom;return this._oldCenterX=this.centerSpringX.current.value,this._oldCenterY=this.centerSpringY.current.value,this._oldZoom=this.zoomSpring.current.value,e},deltaPixelsFromPoints:function(a,b){return a.times(this._containerInnerSize.x*this.getZoom(b))},deltaPointsFromPixels:function(a,b){return a.divide(this._containerInnerSize.x*this.getZoom(b))},pixelFromPoint:function(a,b){return this._pixelFromPoint(a,this.getBounds(b))},_pixelFromPoint:function(b,c){return b.minus(c.getTopLeft()).times(this._containerInnerSize.x/c.width).plus(new a.Point(this._margins.left,this._margins.top))},pointFromPixel:function(b,c){var d=this.getBounds(c);return b.minus(new a.Point(this._margins.left,this._margins.top)).divide(this._containerInnerSize.x/d.width).plus(d.getTopLeft())},_viewportToImageDelta:function(b,c){var d=this.homeBounds.width;return new a.Point(b*(this.contentSize.x/d),c*(this.contentSize.y*this.contentAspectX/d))},viewportToImageCoordinates:function(b,c){return 1==arguments.length?this.viewportToImageCoordinates(b.x,b.y):(this.viewer&&this.viewer.world.getItemCount()>1&&a.console.error("[Viewport.viewportToImageCoordinates] is not accurate with multi-image; use TiledImage.viewportToImageCoordinates instead."),this._viewportToImageDelta(b-this.homeBounds.x,c-this.homeBounds.y))},_imageToViewportDelta:function(b,c){var d=this.homeBounds.width;return new a.Point(b/this.contentSize.x*d,c/this.contentSize.y/this.contentAspectX*d)},imageToViewportCoordinates:function(b,c){if(1==arguments.length)return this.imageToViewportCoordinates(b.x,b.y);this.viewer&&this.viewer.world.getItemCount()>1&&a.console.error("[Viewport.imageToViewportCoordinates] is not accurate with multi-image; use TiledImage.imageToViewportCoordinates instead.");var d=this._imageToViewportDelta(b,c);return d.x+=this.homeBounds.x,d.y+=this.homeBounds.y,d},imageToViewportRectangle:function(b,c,d,e){var f,g,h;return 1==arguments.length?(h=b,this.imageToViewportRectangle(h.x,h.y,h.width,h.height)):(f=this.imageToViewportCoordinates(b,c),g=this._imageToViewportDelta(d,e),new a.Rect(f.x,f.y,g.x,g.y))},viewportToImageRectangle:function(b,c,d,e){var f,g,h;return 1==arguments.length?(h=b,this.viewportToImageRectangle(h.x,h.y,h.width,h.height)):(f=this.viewportToImageCoordinates(b,c),g=this._viewportToImageDelta(d,e),new a.Rect(f.x,f.y,g.x,g.y))},viewerElementToImageCoordinates:function(a){var b=this.pointFromPixel(a,!0);return this.viewportToImageCoordinates(b)},imageToViewerElementCoordinates:function(a){var b=this.imageToViewportCoordinates(a);return this.pixelFromPoint(b,!0)},windowToImageCoordinates:function(a){var b=a.minus(OpenSeadragon.getElementPosition(this.viewer.element));return this.viewerElementToImageCoordinates(b)},imageToWindowCoordinates:function(a){var b=this.imageToViewerElementCoordinates(a);return b.plus(OpenSeadragon.getElementPosition(this.viewer.element))},viewerElementToViewportCoordinates:function(a){return this.pointFromPixel(a,!0)},viewportToViewerElementCoordinates:function(a){return this.pixelFromPoint(a,!0)},windowToViewportCoordinates:function(a){var b=a.minus(OpenSeadragon.getElementPosition(this.viewer.element));return this.viewerElementToViewportCoordinates(b)},viewportToWindowCoordinates:function(a){var b=this.viewportToViewerElementCoordinates(a);return b.plus(OpenSeadragon.getElementPosition(this.viewer.element))},viewportToImageZoom:function(b){this.viewer&&this.viewer.world.getItemCount()>1&&a.console.error("[Viewport.viewportToImageZoom] is not accurate with multi-image.");var c=this.contentSize.x,d=this._containerInnerSize.x,e=this.homeBounds.width,f=d/c*e;return b*f},imageToViewportZoom:function(b){this.viewer&&this.viewer.world.getItemCount()>1&&a.console.error("[Viewport.imageToViewportZoom] is not accurate with multi-image.");var c=this.contentSize.x,d=this._containerInnerSize.x,e=this.homeBounds.width,f=c/d/e;return b*f}}}(OpenSeadragon),function(a){function b(b){b._needsDraw=!1;var d,e,g,h,i,j,l,m,n=null,o=!1,q=a.now(),r=b.viewport.getBoundsWithMargins(!0),s=b.viewport.deltaPixelsFromPoints(b.source.getPixelRatio(0),!0).x*b._scaleSpring.current.value,t=Math.max(b.source.minLevel,Math.floor(Math.log(b.minZoomImageRatio)/Math.log(2))),u=Math.min(Math.abs(b.source.maxLevel),Math.abs(Math.floor(Math.log(s/b.minPixelRatio)/Math.log(2)))),v=b.viewport.degrees;for(r.x-=b._xSpring.current.value,r.y-=b._ySpring.current.value;b.lastDrawn.length>0;)d=b.lastDrawn.pop(),d.beingDrawn=!1;if(90===v||270===v)r=r.rotate(v);else if(0!==v&&180!==v){var w=r.rotate(90);r.x-=w.width/2,r.y-=w.height/2,r.width+=w.width,r.height+=w.height}var x=r.getTopLeft(),y=r.getBottomRight();if(!(!b.wrapHorizontal&&(y.x<0||x.x>b._worldWidthCurrent)||!b.wrapVertical&&(y.y<0||x.y>b._worldHeightCurrent))){b.wrapHorizontal||(x.x=Math.max(x.x,0),y.x=Math.min(y.x,b._worldWidthCurrent)),b.wrapVertical||(x.y=Math.max(x.y,0),y.y=Math.min(y.y,b._worldHeightCurrent)),t=Math.min(t,u);var z;for(e=u;e>=t;e--){if(z=!1,g=b.viewport.deltaPixelsFromPoints(b.source.getPixelRatio(e),!0).x*b._scaleSpring.current.value,!o&&g>=b.minPixelRatio||e==t)z=!0,o=!0;else if(!o)continue;if(h=b.viewport.deltaPixelsFromPoints(b.source.getPixelRatio(e),!1).x*b._scaleSpring.current.value,i=b.viewport.deltaPixelsFromPoints(b.source.getPixelRatio(Math.max(b.source.getClosestLevel(b.viewport.containerSize)-1,0)),!1).x*b._scaleSpring.current.value,j=b.immediateRender?1:i,l=Math.min(1,(g-.5)/.5),m=j/Math.abs(j-h),n=c(b,o,z,e,l,m,x,y,q,n),k(b.coverage,e))break}p(b,b.lastDrawn),n&&!n.context2D&&f(b,n,q)}}function c(a,b,c,e,f,g,h,i,j,k){var l,m,o,p,q,r=a.viewport.pixelFromPoint(a.viewport.getCenter());for(a.viewer&&a.viewer.raiseEvent("update-level",{tiledImage:a,havedrawn:b,level:e,opacity:f,visibility:g,topleft:h,bottomright:i,currenttime:j,best:k}),o=a.source.getTileAtPoint(e,h.divide(a._scaleSpring.current.value)),p=a.source.getTileAtPoint(e,i.divide(a._scaleSpring.current.value)),q=a.source.getNumTiles(e),n(a.coverage,e),a.wrapHorizontal||(p.x=Math.min(p.x,q.x-1)),a.wrapVertical||(p.y=Math.min(p.y,q.y-1)),l=o.x;l<=p.x;l++)for(m=o.y;m<=p.y;m++)k=d(a,c,b,l,m,e,f,g,r,q,j,k);return k}function d(a,b,c,d,f,g,k,n,p,q,r,s){var t=e(d,f,g,a.source,a.tilesMatrix,r,q,a._worldWidthCurrent,a._worldHeightCurrent),u=b;if(a.viewer&&a.viewer.raiseEvent("update-tile",{tiledImage:a,tile:t}),m(a.coverage,g,d,f,!1),!t.exists)return s;if(c&&!u&&(l(a.coverage,g,d,f)?m(a.coverage,g,d,f,!0):u=!0),!u)return s;if(i(t,a.source.tileOverlap,a.viewport,p,n,a),!t.loaded)if(t.context2D)h(a,t);else{var v=a._tileCache.getImageRecord(t.url);if(v){var w=v.getImage();h(a,t,w)}}if(t.loaded){var x=j(a,t,d,f,g,k,r);x&&(a._needsDraw=!0)}else t.loading||(s=o(s,t));return s}function e(b,c,d,e,f,g,h,i,j){var k,l,m,n,o,p,q;return f[d]||(f[d]={}),f[d][b]||(f[d][b]={}),f[d][b][c]||(k=(h.x+b%h.x)%h.x,l=(h.y+c%h.y)%h.y,m=e.getTileBounds(d,k,l),n=e.tileExists(d,k,l),o=e.getTileUrl(d,k,l),p=e.getContext2D?e.getContext2D(d,k,l):void 0,m.x+=(b-k)/h.x,m.y+=j/i*((c-l)/h.y),f[d][b][c]=new a.Tile(d,b,c,m,n,o,p)),q=f[d][b][c],q.lastTouchTime=g,q}function f(a,b,c){b.loading=!0,a._imageLoader.addJob({src:b.url,crossOriginPolicy:a.crossOriginPolicy,callback:function(d,e){g(a,b,c,d,e)},abort:function(){b.loading=!1}})}function g(b,c,d,e,f){if(e){if(dh)return!0;return!1}function k(a,b,c,d){var e,f,g,h;if(!a[b])return!1;if(void 0===c||void 0===d){e=a[b];for(g in e)if(e.hasOwnProperty(g)){f=e[g];for(h in f)if(f.hasOwnProperty(h)&&!f[h])return!1}return!0}return void 0===a[b][c]||void 0===a[b][c][d]||a[b][c][d]===!0}function l(a,b,c,d){return void 0===c||void 0===d?k(a,b+1):k(a,b+1,2*c,2*d)&&k(a,b+1,2*c,2*d+1)&&k(a,b+1,2*c+1,2*d)&&k(a,b+1,2*c+1,2*d+1)}function m(b,c,d,e,f){return b[c]?(b[c][d]||(b[c][d]={}),void(b[c][d][e]=f)):void a.console.warn("Setting coverage for a tile before its level's coverage has been reset: %s",c)}function n(a,b){a[b]={}}function o(a,b){return a?b.visibility>a.visibility?b:b.visibility==a.visibility&&b.distance=0;c--)d=b[c],a._drawer.drawTile(d,a._drawingHandler,e),d.beingDrawn=!0,a.viewer&&a.viewer.raiseEvent("tile-drawn",{tiledImage:a,tile:d});f&&a._drawer.restoreContext(e),e&&a._drawer.blendSketch(a.opacity),q(a,b)}function q(b,c){if(b.debugMode)for(var d=c.length-1;d>=0;d--){var e=c[d];try{b._drawer.drawDebugInfo(e,c.length,d)}catch(f){a.console.error(f)}}}a.TiledImage=function(b){var c=this;a.console.assert(b.tileCache,"[TiledImage] options.tileCache is required"),a.console.assert(b.drawer,"[TiledImage] options.drawer is required"),a.console.assert(b.viewer,"[TiledImage] options.viewer is required"),a.console.assert(b.imageLoader,"[TiledImage] options.imageLoader is required"),a.console.assert(b.source,"[TiledImage] options.source is required"),a.console.assert(!b.clip||b.clip instanceof a.Rect,"[TiledImage] options.clip must be an OpenSeadragon.Rect if present"),a.EventSource.call(this),this._tileCache=b.tileCache,delete b.tileCache,this._drawer=b.drawer,delete b.drawer,this._imageLoader=b.imageLoader,delete b.imageLoader,b.clip instanceof a.Rect&&(this._clip=b.clip.clone()),delete b.clip;var d=b.x||0;delete b.x;var e=b.y||0;delete b.y,this.normHeight=b.source.dimensions.y/b.source.dimensions.x,this.contentAspectX=b.source.dimensions.x/b.source.dimensions.y;var f=1;b.width?(f=b.width,delete b.width,b.height&&(a.console.error("specifying both width and height to a tiledImage is not supported"),delete b.height)):b.height&&(f=b.height/this.normHeight,delete b.height),a.extend(!0,this,{viewer:null,tilesMatrix:{},coverage:{},lastDrawn:[],lastResetTime:0,_midDraw:!1,_needsDraw:!0,_hasOpaqueTile:!1,springStiffness:a.DEFAULT_SETTINGS.springStiffness,animationTime:a.DEFAULT_SETTINGS.animationTime,minZoomImageRatio:a.DEFAULT_SETTINGS.minZoomImageRatio,wrapHorizontal:a.DEFAULT_SETTINGS.wrapHorizontal,wrapVertical:a.DEFAULT_SETTINGS.wrapVertical,immediateRender:a.DEFAULT_SETTINGS.immediateRender,blendTime:a.DEFAULT_SETTINGS.blendTime,alwaysBlend:a.DEFAULT_SETTINGS.alwaysBlend,minPixelRatio:a.DEFAULT_SETTINGS.minPixelRatio,debugMode:a.DEFAULT_SETTINGS.debugMode,crossOriginPolicy:a.DEFAULT_SETTINGS.crossOriginPolicy,placeholderFillStyle:a.DEFAULT_SETTINGS.placeholderFillStyle,opacity:a.DEFAULT_SETTINGS.opacity},b),this._xSpring=new a.Spring({initial:d,springStiffness:this.springStiffness,animationTime:this.animationTime}),this._ySpring=new a.Spring({initial:e,springStiffness:this.springStiffness,animationTime:this.animationTime}),this._scaleSpring=new a.Spring({initial:f,springStiffness:this.springStiffness,animationTime:this.animationTime}),this._updateForScale(),this._drawingHandler=function(b){c.viewer.raiseEvent("tile-drawing",a.extend({tiledImage:c},b))}},a.extend(a.TiledImage.prototype,a.EventSource.prototype,{needsDraw:function(){return this._needsDraw},reset:function(){this._tileCache.clearTilesFor(this),this.lastResetTime=a.now(),this._needsDraw=!0},update:function(){var a=this._xSpring.current.value,b=this._ySpring.current.value,c=this._scaleSpring.current.value;return this._xSpring.update(),this._ySpring.update(),this._scaleSpring.update(),this._xSpring.current.value!==a||this._ySpring.current.value!==b||this._scaleSpring.current.value!==c?(this._updateForScale(),this._needsDraw=!0,!0):!1},draw:function(){this._midDraw=!0,b(this),this._midDraw=!1},destroy:function(){this.reset()},getBounds:function(b){return b?new a.Rect(this._xSpring.current.value,this._ySpring.current.value,this._worldWidthCurrent,this._worldHeightCurrent):new a.Rect(this._xSpring.target.value,this._ySpring.target.value,this._worldWidthTarget,this._worldHeightTarget)},getWorldBounds:function(){return a.console.error("[TiledImage.getWorldBounds] is deprecated; use TiledImage.getBounds instead"),this.getBounds()},getContentSize:function(){return new a.Point(this.source.dimensions.x,this.source.dimensions.y)},_viewportToImageDelta:function(b,c,d){var e=d?this._scaleSpring.current.value:this._scaleSpring.target.value;return new a.Point(b*(this.source.dimensions.x/e),c*(this.source.dimensions.y*this.contentAspectX/e))},viewportToImageCoordinates:function(b,c,d){return b instanceof a.Point&&(d=c,c=b.y,b=b.x),d?this._viewportToImageDelta(b-this._xSpring.current.value,c-this._ySpring.current.value):this._viewportToImageDelta(b-this._xSpring.target.value,c-this._ySpring.target.value)},_imageToViewportDelta:function(b,c,d){var e=d?this._scaleSpring.current.value:this._scaleSpring.target.value;return new a.Point(b/this.source.dimensions.x*e,c/this.source.dimensions.y/this.contentAspectX*e)},imageToViewportCoordinates:function(b,c,d){b instanceof a.Point&&(d=c,c=b.y,b=b.x);var e=this._imageToViewportDelta(b,c);return d?(e.x+=this._xSpring.current.value,e.y+=this._ySpring.current.value):(e.x+=this._xSpring.target.value,e.y+=this._ySpring.target.value),e},imageToViewportRectangle:function(b,c,d,e,f){b instanceof a.Rect&&(f=c,d=b.width,e=b.height,c=b.y,b=b.x);var g=this.imageToViewportCoordinates(b,c,f),h=this._imageToViewportDelta(d,e,f);return new a.Rect(g.x,g.y,h.x,h.y)},viewportToImageRectangle:function(b,c,d,e,f){b instanceof a.Rect&&(f=c,d=b.width,e=b.height,c=b.y,b=b.x);var g=this.viewportToImageCoordinates(b,c,f),h=this._viewportToImageDelta(d,e,f);return new a.Rect(g.x,g.y,h.x,h.y)},viewerElementToImageCoordinates:function(a){var b=this.viewport.pointFromPixel(a,!0);return this.viewportToImageCoordinates(b)},imageToViewerElementCoordinates:function(a){var b=this.imageToViewportCoordinates(a);return this.viewport.pixelFromPoint(b,!0)},windowToImageCoordinates:function(a){var b=a.minus(OpenSeadragon.getElementPosition(this.viewer.element));return this.viewerElementToImageCoordinates(b)},imageToWindowCoordinates:function(a){var b=this.imageToViewerElementCoordinates(a);return b.plus(OpenSeadragon.getElementPosition(this.viewer.element))},viewportToImageZoom:function(a){var b=this._scaleSpring.current.value*this.viewport._containerInnerSize.x/this.source.dimensions.x;return b*a},imageToViewportZoom:function(a){var b=this._scaleSpring.current.value*this.viewport._containerInnerSize.x/this.source.dimensions.x;return a/b},setPosition:function(a,b){var c=this._xSpring.target.value===a.x&&this._ySpring.target.value===a.y;if(b){if(c&&this._xSpring.current.value===a.x&&this._ySpring.current.value===a.y)return;this._xSpring.resetTo(a.x),this._ySpring.resetTo(a.y),this._needsDraw=!0}else{if(c)return;this._xSpring.springTo(a.x),this._ySpring.springTo(a.y),this._needsDraw=!0}c||this._raiseBoundsChange()},setWidth:function(a,b){this._setScale(a,b)},setHeight:function(a,b){this._setScale(a/this.normHeight,b)},getClip:function(){return this._clip?this._clip.clone():null},setClip:function(b){a.console.assert(!b||b instanceof a.Rect,"[TiledImage.setClip] newClip must be an OpenSeadragon.Rect or null"),b instanceof a.Rect?this._clip=b.clone():this._clip=null,this._needsDraw=!0},getOpacity:function(){return this.opacity},setOpacity:function(a){this.opacity=a,this._needsDraw=!0},_setScale:function(a,b){var c=this._scaleSpring.target.value===a;if(b){if(c&&this._scaleSpring.current.value===a)return;this._scaleSpring.resetTo(a),this._updateForScale(),this._needsDraw=!0}else{if(c)return;this._scaleSpring.springTo(a),this._updateForScale(),this._needsDraw=!0}c||this._raiseBoundsChange()},_updateForScale:function(){this._worldWidthTarget=this._scaleSpring.target.value,this._worldHeightTarget=this.normHeight*this._scaleSpring.target.value,this._worldWidthCurrent=this._scaleSpring.current.value,this._worldHeightCurrent=this.normHeight*this._scaleSpring.current.value},_raiseBoundsChange:function(){this.raiseEvent("bounds-change")}})}(OpenSeadragon),function(a){var b=function(b){a.console.assert(b,"[TileCache.cacheTile] options is required"),a.console.assert(b.tile,"[TileCache.cacheTile] options.tile is required"),a.console.assert(b.tiledImage,"[TileCache.cacheTile] options.tiledImage is required"),this.tile=b.tile,this.tiledImage=b.tiledImage},c=function(b){a.console.assert(b,"[ImageRecord] options is required"),a.console.assert(b.image,"[ImageRecord] options.image is required"),this._image=b.image,this._tiles=[]};c.prototype={destroy:function(){this._image=null,this._renderedContext=null,this._tiles=null},getImage:function(){return this._image},getRenderedContext:function(){if(!this._renderedContext){var a=document.createElement("canvas");a.width=this._image.width,a.height=this._image.height,this._renderedContext=a.getContext("2d"),this._renderedContext.drawImage(this._image,0,0),this._image=null}return this._renderedContext},setRenderedContext:function(b){a.console.error("ImageRecord.setRenderedContext is deprecated. The rendered context should be created by the ImageRecord itself when calling ImageRecord.getRenderedContext."),this._renderedContext=b},addTile:function(b){a.console.assert(b,"[ImageRecord.addTile] tile is required"),this._tiles.push(b)},removeTile:function(b){for(var c=0;cthis._maxImageCacheCount){for(var h,i,j,k,l,m,n=null,o=-1,p=null,q=this._tilesLoaded.length-1;q>=0;q--)m=this._tilesLoaded[q],h=m.tile,h.level<=e||h.beingDrawn||(n?(k=h.lastTouchTime,i=n.lastTouchTime,l=h.level,j=n.level,(i>k||k==i&&l>j)&&(n=h,o=q,p=m)):(n=h,o=q,p=m));n&&o>=0&&(this._unloadTile(p),f=o)}this._tilesLoaded[f]=new b({tile:d.tile,tiledImage:d.tiledImage})},clearTilesFor:function(b){a.console.assert(b,"[TileCache.clearTilesFor] tiledImage is required");for(var c,d=0;d=this._items.length)throw new Error("Index bigger than number of layers.");c!==d&&-1!==d&&(this._items.splice(d,1),this._items.splice(c,0,b),this._needsDraw=!0,this.raiseEvent("item-index-change",{item:b,previousIndex:d,newIndex:c}))},removeItem:function(b){a.console.assert(b,"[World.removeItem] item is required");var c=a.indexOf(this._items,b);-1!==c&&(b.removeHandler("bounds-change",this._delegatedFigureSizes),b.destroy(),this._items.splice(c,1),this._figureSizes(),this._needsDraw=!0,this._raiseRemoveItem(b))},removeAll:function(){this.viewer._cancelPendingImages();for(var a,b=0;bl.height?h:h*(l.width/l.height),n=m*(l.height/l.width),o=new a.Point(p+(h-m)/2,q+(h-n)/2),k.setPosition(o,d),k.setWidth(m,d),"horizontal"===e?p+=j:q+=j;this.setAutoRefigureSizes(!0)},_figureSizes:function(){var b=this._homeBounds?this._homeBounds.clone():null,c=this._contentSize?this._contentSize.clone():null,d=this._contentFactor||0;if(this._items.length){var e=this._items[0].getBounds();this._contentFactor=this._items[0].getContentSize().x/e.width;for(var f,g=e.x,h=e.y,i=e.x+e.width,j=e.y+e.height,k=1;kj;j++)if(a=arguments[j],null!==a||void 0!==a)for(b in a)c=g[b],d=a[b],g!==d&&(i&&d&&(OpenSeadragon.isPlainObject(d)||(e=OpenSeadragon.isArray(d)))?(e?(e=!1,f=c&&OpenSeadragon.isArray(c)?c:[]):f=c&&OpenSeadragon.isPlainObject(c)?c:{},g[b]=OpenSeadragon.extend(i,f,d)):void 0!==d&&(g[b]=d));return g},a.extend(a,{DEFAULT_SETTINGS:{xmlPath:null,tileSources:null,tileHost:null,initialPage:0,crossOriginPolicy:!1,ajaxWithCredentials:!1,panHorizontal:!0,panVertical:!0,constrainDuringPan:!1,wrapHorizontal:!1,wrapVertical:!1,visibilityRatio:.5,minPixelRatio:.5,defaultZoomLevel:0,minZoomLevel:null,maxZoomLevel:null,homeFillsViewer:!1,clickTimeThreshold:300,clickDistThreshold:5,dblClickTimeThreshold:300,dblClickDistThreshold:20,springStiffness:6.5,animationTime:1.2,gestureSettingsMouse:{scrollToZoom:!0,clickToZoom:!0,dblClickToZoom:!1,pinchToZoom:!1,flickEnabled:!1,flickMinSpeed:120,flickMomentum:.25,pinchRotate:!1},gestureSettingsTouch:{scrollToZoom:!1,clickToZoom:!1,dblClickToZoom:!0,pinchToZoom:!0,flickEnabled:!0,flickMinSpeed:120,flickMomentum:.25,pinchRotate:!1},gestureSettingsPen:{scrollToZoom:!1,clickToZoom:!0,dblClickToZoom:!1,pinchToZoom:!1,flickEnabled:!1,flickMinSpeed:120,flickMomentum:.25,pinchRotate:!1},gestureSettingsUnknown:{scrollToZoom:!1,clickToZoom:!1,dblClickToZoom:!0,pinchToZoom:!0,flickEnabled:!0,flickMinSpeed:120,flickMomentum:.25,pinchRotate:!1},zoomPerClick:2,zoomPerScroll:1.2,zoomPerSecond:1,blendTime:0,alwaysBlend:!1,autoHideControls:!0,immediateRender:!1,minZoomImageRatio:.9,maxZoomPixelRatio:1.1,pixelsPerWheelLine:40,autoResize:!0,showSequenceControl:!0,sequenceControlAnchor:null,preserveViewport:!1,preserveOverlays:!1,navPrevNextWrap:!1,showNavigationControl:!0,navigationControlAnchor:null,showZoomControl:!0,showHomeControl:!0,showFullPageControl:!0,showRotationControl:!1,controlsFadeDelay:2e3,controlsFadeLength:1500,mouseNavEnabled:!0,showNavigator:!1,navigatorId:null,navigatorPosition:null,navigatorSizeRatio:.2,navigatorMaintainSizeRatio:!1,navigatorTop:null,navigatorLeft:null,navigatorHeight:null,navigatorWidth:null,navigatorAutoResize:!0,navigatorRotate:!0,degrees:0,opacity:1,placeholderFillStyle:null,showReferenceStrip:!1,referenceStripScroll:"horizontal",referenceStripElement:null,referenceStripHeight:null,referenceStripWidth:null,referenceStripPosition:"BOTTOM_LEFT",referenceStripSizeRatio:.2,collectionRows:3,collectionLayout:"horizontal",collectionMode:!1,collectionTileSize:800,collectionTileMargin:80,imageLoaderLimit:0,maxImageCacheCount:200,timeout:3e4,useCanvas:!0,prefixUrl:"/images/",navImages:{zoomIn:{REST:"zoomin_rest.png",GROUP:"zoomin_grouphover.png",HOVER:"zoomin_hover.png",DOWN:"zoomin_pressed.png"},zoomOut:{REST:"zoomout_rest.png",GROUP:"zoomout_grouphover.png",HOVER:"zoomout_hover.png",DOWN:"zoomout_pressed.png"},home:{REST:"home_rest.png",GROUP:"home_grouphover.png",HOVER:"home_hover.png",DOWN:"home_pressed.png"},fullpage:{REST:"fullpage_rest.png",GROUP:"fullpage_grouphover.png",HOVER:"fullpage_hover.png",DOWN:"fullpage_pressed.png"},rotateleft:{REST:"rotateleft_rest.png",GROUP:"rotateleft_grouphover.png",HOVER:"rotateleft_hover.png",DOWN:"rotateleft_pressed.png"},rotateright:{REST:"rotateright_rest.png",GROUP:"rotateright_grouphover.png",HOVER:"rotateright_hover.png",DOWN:"rotateright_pressed.png"},previous:{REST:"previous_rest.png",GROUP:"previous_grouphover.png",HOVER:"previous_hover.png",DOWN:"previous_pressed.png"},next:{REST:"next_rest.png",GROUP:"next_grouphover.png",HOVER:"next_hover.png",DOWN:"next_pressed.png"}},debugMode:!1,debugGridColor:"#437AB2"},SIGNAL:"----seadragon----",delegate:function(a,b){return function(){var c=arguments;return void 0===c&&(c=[]),b.apply(a,c)}},BROWSERS:{UNKNOWN:0,IE:1,FIREFOX:2,SAFARI:3,CHROME:4,OPERA:5},getElement:function(a){return"string"==typeof a&&(a=document.getElementById(a)),a},getElementPosition:function(c){var d,e,f=new a.Point;for(c=a.getElement(c),d="fixed"==a.getElementStyle(c).position,e=b(c,d);e;)f.x+=c.offsetLeft,f.y+=c.offsetTop,d&&(f=f.plus(a.getPageScroll())),c=e,d="fixed"==a.getElementStyle(c).position,e=b(c,d);return f},getElementOffset:function(b){b=a.getElement(b);var c,d,e=b&&b.ownerDocument,f={top:0,left:0};return e?(c=e.documentElement,"undefined"!=typeof b.getBoundingClientRect&&(f=b.getBoundingClientRect()),d=e==e.window?e:9===e.nodeType?e.defaultView||e.parentWindow:!1,new a.Point(f.left+(d.pageXOffset||c.scrollLeft)-(c.clientLeft||0),f.top+(d.pageYOffset||c.scrollTop)-(c.clientTop||0))):new a.Point},getElementSize:function(b){return b=a.getElement(b),new a.Point(b.clientWidth,b.clientHeight)},getElementStyle:document.documentElement.currentStyle?function(b){return b=a.getElement(b),b.currentStyle}:function(b){return b=a.getElement(b),window.getComputedStyle(b,"")},pointInElement:function(b,c){b=a.getElement(b);var d=a.getElementOffset(b),e=a.getElementSize(b);return c.x>=d.x&&c.x=d.y},getEvent:function(b){return a.getEvent=b?function(a){return a}:function(){return window.event},a.getEvent(b)},getMousePosition:function(b){if("number"==typeof b.pageX)a.getMousePosition=function(b){var c=new a.Point;return b=a.getEvent(b),c.x=b.pageX,c.y=b.pageY,c};else{if("number"!=typeof b.clientX)throw new Error("Unknown event mouse position, no known technique.");a.getMousePosition=function(b){var c=new a.Point;return b=a.getEvent(b),c.x=b.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,c.y=b.clientY+document.body.scrollTop+document.documentElement.scrollTop,c}}return a.getMousePosition(b)},getPageScroll:function(){var b=document.documentElement||{},c=document.body||{};if("number"==typeof window.pageXOffset)a.getPageScroll=function(){return new a.Point(window.pageXOffset,window.pageYOffset)};else if(c.scrollLeft||c.scrollTop)a.getPageScroll=function(){return new a.Point(document.body.scrollLeft,document.body.scrollTop)};else{if(!b.scrollLeft&&!b.scrollTop)return new a.Point(0,0);a.getPageScroll=function(){return new a.Point(document.documentElement.scrollLeft,document.documentElement.scrollTop)}}return a.getPageScroll()},setPageScroll:function(b){if("undefined"!=typeof window.scrollTo)a.setPageScroll=function(a){window.scrollTo(a.x,a.y)};else{var c=a.getPageScroll();if(c.x===b.x&&c.y===b.y)return;document.body.scrollLeft=b.x,document.body.scrollTop=b.y;var d=a.getPageScroll();if(d.x!==c.x&&d.y!==c.y)return void(a.setPageScroll=function(a){document.body.scrollLeft=a.x,document.body.scrollTop=a.y});if(document.documentElement.scrollLeft=b.x,document.documentElement.scrollTop=b.y,d=a.getPageScroll(),d.x!==c.x&&d.y!==c.y)return void(a.setPageScroll=function(a){document.documentElement.scrollLeft=a.x,document.documentElement.scrollTop=a.y});a.setPageScroll=function(){}}return a.setPageScroll(b)},getWindowSize:function(){var b=document.documentElement||{},c=document.body||{};if("number"==typeof window.innerWidth)a.getWindowSize=function(){return new a.Point(window.innerWidth,window.innerHeight)};else if(b.clientWidth||b.clientHeight)a.getWindowSize=function(){return new a.Point(document.documentElement.clientWidth,document.documentElement.clientHeight)};else{if(!c.clientWidth&&!c.clientHeight)throw new Error("Unknown window size, no known technique.");a.getWindowSize=function(){return new a.Point(document.body.clientWidth,document.body.clientHeight)}}return a.getWindowSize()},makeCenteredNode:function(b){b=a.getElement(b);var c=[a.makeNeutralElement("div"),a.makeNeutralElement("div"),a.makeNeutralElement("div")];return a.extend(c[0].style,{display:"table",height:"100%",width:"100%"}),a.extend(c[1].style,{display:"table-row"}),a.extend(c[2].style,{display:"table-cell",verticalAlign:"middle",textAlign:"center"}),c[0].appendChild(c[1]),c[1].appendChild(c[2]),c[2].appendChild(b),c[0]},makeNeutralElement:function(a){var b=document.createElement(a),c=b.style;return c.background="transparent none",c.border="none",c.margin="0px",c.padding="0px",c.position="static",b},now:function(){return a.now=Date.now?Date.now:function(){return(new Date).getTime()},a.now()},makeTransparentImage:function(b){return a.makeTransparentImage=function(b){var c=a.makeNeutralElement("img");return c.src=b,c},a.Browser.vendor==a.BROWSERS.IE&&a.Browser.version<7&&(a.makeTransparentImage=function(b){var c=a.makeNeutralElement("img"),d=null;return d=a.makeNeutralElement("span"),d.style.display="inline-block",c.onload=function(){d.style.width=d.style.width||c.width+"px",d.style.height=d.style.height||c.height+"px",c.onload=null,c=null},c.src=b,d.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+b+"', sizingMethod='scale')",d}),a.makeTransparentImage(b)},setElementOpacity:function(b,c,d){var e,f;b=a.getElement(b),d&&!a.Browser.alpha&&(c=Math.round(c)),a.Browser.opacity?b.style.opacity=1>c?c:"":1>c?(e=Math.round(100*c),f="alpha(opacity="+e+")",b.style.filter=f):b.style.filter=""},setElementTouchActionNone:function(b){b=a.getElement(b),"undefined"!=typeof b.style.touchAction?b.style.touchAction="none":"undefined"!=typeof b.style.msTouchAction&&(b.style.msTouchAction="none")},addClass:function(b,c){b=a.getElement(b),b.className?-1===(" "+b.className+" ").indexOf(" "+c+" ")&&(b.className+=" "+c):b.className=c},indexOf:function(a,b,c){return this.indexOf=Array.prototype.indexOf?function(a,b,c){return a.indexOf(b,c)}:function(a,b,c){var d,e,f=c?c:0;if(!a)throw new TypeError;if(e=a.length,0===e||f>=e)return-1;for(0>f&&(f=e-Math.abs(f)),d=f;e>d;d++)if(a[d]===b)return d;return-1},this.indexOf(a,b,c)},removeClass:function(b,c){var d,e,f=[];for(b=a.getElement(b),d=b.className.split(/\s+/),e=0;e=0?(a.Browser.vendor=a.BROWSERS.FIREFOX,a.Browser.version=parseFloat(e.substring(e.indexOf("Firefox")+8))):e.indexOf("Safari")>=0?(a.Browser.vendor=e.indexOf("Chrome")>=0?a.BROWSERS.CHROME:a.BROWSERS.SAFARI,a.Browser.version=parseFloat(e.substring(e.substring(0,e.indexOf("Safari")).lastIndexOf("/")+1,e.indexOf("Safari")))):(b=new RegExp("Trident/.*rv:([0-9]{1,}[.0-9]{0,})"),null!==b.exec(e)&&(a.Browser.vendor=a.BROWSERS.IE,a.Browser.version=parseFloat(RegExp.$1))));break;case"Opera":a.Browser.vendor=a.BROWSERS.OPERA,a.Browser.version=parseFloat(c)}var f,g,h,i=window.location.search.substring(1),j=i.split("&");for(h=0;h0&&(d[f.substring(0,g)]=decodeURIComponent(f.substring(g+1)));a.Browser.alpha=!(a.Browser.vendor==a.BROWSERS.IE&&a.Browser.version<9||a.Browser.vendor==a.BROWSERS.CHROME&&a.Browser.version<2),a.Browser.opacity=!(a.Browser.vendor==a.BROWSERS.IE&&a.Browser.version<9)}();var e=function(){};a.console=window.console||{log:e,debug:e,info:e,warn:e,error:e,assert:e},function(b){var c=b.requestAnimationFrame||b.mozRequestAnimationFrame||b.webkitRequestAnimationFrame||b.msRequestAnimationFrame,d=b.cancelAnimationFrame||b.mozCancelAnimationFrame||b.webkitCancelAnimationFrame||b.msCancelAnimationFrame;if(c&&d)a.requestAnimationFrame=function(){return c.apply(b,arguments)},a.cancelAnimationFrame=function(){return d.apply(b,arguments)};else{var e,f=[],g=[],h=0;a.requestAnimationFrame=function(b){return f.push([++h,b]),e||(e=setInterval(function(){if(f.length){var b=a.now(),c=g;for(g=f,f=c;g.length;)g.shift()[1](b)}else clearInterval(e),e=void 0},20)),h},a.cancelAnimationFrame=function(a){var b,c;for(b=0,c=f.length;c>b;b+=1)if(f[b][0]===a)return void f.splice(b,1);for(b=0,c=g.length;c>b;b+=1)if(g[b][0]===a)return void g.splice(b,1)}}}(window),a._processDZIError=function(a){var b=a.getElementsByTagName("Message")[0],c=b.firstChild.nodeValue;throw new Error(c)}}(OpenSeadragon),function(a){var b={supportsFullScreen:!1,isFullScreen:function(){return!1},getFullScreenElement:function(){return null},requestFullScreen:function(){},exitFullScreen:function(){},cancelFullScreen:function(){},fullScreenEventName:"",fullScreenErrorEventName:""};document.exitFullscreen?(b.supportsFullScreen=!0,b.getFullScreenElement=function(){return document.fullscreenElement},b.requestFullScreen=function(a){return a.requestFullscreen()},b.exitFullScreen=function(){document.exitFullscreen()},b.fullScreenEventName="fullscreenchange",b.fullScreenErrorEventName="fullscreenerror"):document.msExitFullscreen?(b.supportsFullScreen=!0,b.getFullScreenElement=function(){return document.msFullscreenElement},b.requestFullScreen=function(a){return a.msRequestFullscreen()},b.exitFullScreen=function(){document.msExitFullscreen()},b.fullScreenEventName="MSFullscreenChange",b.fullScreenErrorEventName="MSFullscreenError"):document.webkitExitFullscreen?(b.supportsFullScreen=!0,b.getFullScreenElement=function(){return document.webkitFullscreenElement},b.requestFullScreen=function(a){return a.webkitRequestFullscreen()},b.exitFullScreen=function(){document.webkitExitFullscreen()},b.fullScreenEventName="webkitfullscreenchange",b.fullScreenErrorEventName="webkitfullscreenerror"):document.webkitCancelFullScreen?(b.supportsFullScreen=!0,b.getFullScreenElement=function(){return document.webkitCurrentFullScreenElement},b.requestFullScreen=function(a){return a.webkitRequestFullScreen()},b.exitFullScreen=function(){document.webkitCancelFullScreen()},b.fullScreenEventName="webkitfullscreenchange",b.fullScreenErrorEventName="webkitfullscreenerror"):document.mozCancelFullScreen&&(b.supportsFullScreen=!0,b.getFullScreenElement=function(){return document.mozFullScreenElement},b.requestFullScreen=function(a){return a.mozRequestFullScreen()},b.exitFullScreen=function(){document.mozCancelFullScreen()},b.fullScreenEventName="mozfullscreenchange",b.fullScreenErrorEventName="mozfullscreenerror"),b.isFullScreen=function(){return null!==b.getFullScreenElement()},b.cancelFullScreen=function(){a.console.error("cancelFullScreen is deprecated. Use exitFullScreen instead."),b.exitFullScreen()},a.extend(a,b)}(OpenSeadragon),function(a){a.EventSource=function(){this.events={}},a.EventSource.prototype={addHandler:function(b,c,d){var e=this.events[b];e||(this.events[b]=e=[]),c&&a.isFunction(c)&&(e[e.length]={handler:c,userData:d||null})},removeHandler:function(b,c){var d,e=this.events[b],f=[];if(e&&a.isArray(e)){for(d=0;dd;d++)b[d]&&(c.eventSource=a,c.userData=b[d].userData,b[d].handler(c))}):null},raiseEvent:function(a,b){var c=this.getHandler(a);c&&(b||(b={}),c(this,b))}}}(OpenSeadragon),function(a){function b(b){var c,d=ob[b.hash],e=d.activePointersLists.length;for(c=0;e>c;c++)d.activePointersLists[c].captureCount>0&&(a.removeEvent(a.MouseTracker.captureElement,"mousemove",d.mousemovecaptured,!0),a.removeEvent(a.MouseTracker.captureElement,"mouseup",d.mouseupcaptured,!0),a.removeEvent(a.MouseTracker.captureElement,a.MouseTracker.unprefixedPointerEvents?"pointermove":"MSPointerMove",d.pointermovecaptured,!0),a.removeEvent(a.MouseTracker.captureElement,a.MouseTracker.unprefixedPointerEvents?"pointerup":"MSPointerUp",d.pointerupcaptured,!0),a.removeEvent(a.MouseTracker.captureElement,"touchmove",d.touchmovecaptured,!0),a.removeEvent(a.MouseTracker.captureElement,"touchend",d.touchendcaptured,!0),d.activePointersLists[c].captureCount=0);for(c=0;e>c;c++)d.activePointersLists.pop()}function c(c){var d,e,f=ob[c.hash];if(!f.tracking){for(e=0;ed;d++)f.push(c.getByIndex(d));f.length>0&&(jb(a,b,f,0),c.captureCount=1,g(a,"touch"),hb(a,b,f))}function M(b,c){var d,e,g,h,j=c.changedTouches.length,k=[],l=b.getActivePointersListByType("touch");for(d=a.now(),l.getLength()>c.touches.length-j&&(a.console.warn("Tracked touch contact count doesn't match event.touches.length. Removing all tracked touch pointers."),L(b,c,l)),e=0;j>e;e++)k.push({id:c.changedTouches[e].identifier,type:"touch",currentPos:i(c.changedTouches[e]),currentTime:d});for(gb(b,c,k),e=0;eg;g++)h.push({id:c.changedTouches[g].identifier,type:"touch",currentPos:i(c.changedTouches[g]),currentTime:d});gb(nb[e],c,h)}ib(b,c,k,0)&&(a.stopEvent(c),f(b,"touch")),a.cancelEvent(c)}function N(a,b){P(a,b)}function O(b,c){P(b,c),a.stopEvent(c)}function P(b,c){var d,e,f,h,j=c.changedTouches.length,k=[];for(d=a.now(),e=0;j>e;e++)k.push({id:c.changedTouches[e].identifier,type:"touch",currentPos:i(c.changedTouches[e]),currentTime:d});for(jb(b,c,k,0)&&g(b,"touch"),hb(b,c,k),e=0;ef;f++)h.push({id:c.changedTouches[f].identifier,type:"touch",currentPos:i(c.changedTouches[f]),currentTime:d});hb(nb[e],c,h)}a.cancelEvent(c)}function Q(a,b){S(a,b)}function R(b,c){S(b,c),a.stopEvent(c)}function S(b,c){var d,e=c.changedTouches.length,f=[];for(d=0;e>d;d++)f.push({id:c.changedTouches[d].identifier,type:"touch",currentPos:i(c.changedTouches[d]),currentTime:a.now()});kb(b,c,f),a.cancelEvent(c)}function T(a,b){var c,d=b.changedTouches.length,e=[];for(c=0;d>c;c++)e.push({id:b.changedTouches[c].identifier,type:"touch"});lb(a,b,e)}function U(a,b){return b.stopPropagation(),b.preventDefault(),!1}function V(a,b){return b.stopPropagation(),b.preventDefault(),!1}function W(b,c){var d;c.currentTarget===c.relatedTarget||w(c.currentTarget,c.relatedTarget)||(d={id:c.pointerId,type:h(c),isPrimary:c.isPrimary,currentPos:i(c),currentTime:a.now()},gb(b,c,[d]))}function X(b,c){var d;c.currentTarget===c.relatedTarget||w(c.currentTarget,c.relatedTarget)||(d={id:c.pointerId,type:h(c),isPrimary:c.isPrimary,currentPos:i(c),currentTime:a.now()},hb(b,c,[d]))}function Y(b,c){var d;d={id:c.pointerId,type:h(c),isPrimary:c.isPrimary,currentPos:i(c),currentTime:a.now()},ib(b,c,[d],c.button)&&(a.stopEvent(c),f(b,d.type)),(b.clickHandler||b.dblClickHandler||b.pressHandler||b.dragHandler||b.dragEndHandler||b.pinchHandler)&&a.cancelEvent(c)}function Z(a,b){_(a,b)}function $(b,c){var d=b.getActivePointersListByType(h(c));d.getById(c.pointerId)&&_(b,c),a.stopEvent(c)}function _(b,c){var d;d={id:c.pointerId,type:h(c),isPrimary:c.isPrimary,currentPos:i(c),currentTime:a.now()},jb(b,c,[d],c.button)&&g(b,d.type)}function ab(a,b){cb(a,b)}function bb(b,c){var d=b.getActivePointersListByType(h(c));d.getById(c.pointerId)&&cb(b,c),a.stopEvent(c)}function cb(b,c){var d;d={id:c.pointerId,type:h(c),isPrimary:c.isPrimary,currentPos:i(c),currentTime:a.now()},kb(b,c,[d])}function db(a,b){var c;c={id:b.pointerId,type:h(b)},lb(a,b,[c])}function eb(a,b){return b.hasOwnProperty("isPrimary")||(b.isPrimary=0===a.getLength()?!0:!1),b.speed=0,b.direction=0,b.contactPos=b.currentPos,b.contactTime=b.currentTime,b.lastPos=b.currentPos,b.lastTime=b.currentTime,a.add(b)}function fb(a,b){var c,d;return a.getById(b.id)?(c=a.removeById(b.id),b.hasOwnProperty("isPrimary")||(d=a.getPrimary(),d||(d=a.getByIndex(0),d&&(d.isPrimary=!0)))):c=a.getLength(),c}function gb(b,c,d){var e,f,g,h,i=b.getActivePointersListByType(d[0].type),j=d.length;for(e=0;j>e;e++)f=d[e],g=i.getById(f.id),g?(g.insideElement=!0,g.lastPos=g.currentPos,g.lastTime=g.currentTime,g.currentPos=f.currentPos,g.currentTime=f.currentTime,f=g):(f.captured=!1,f.insideElementPressed=!1,f.insideElement=!0,eb(i,f)),b.enterHandler&&(h=b.enterHandler({eventSource:b,pointerType:f.type,position:k(f.currentPos,b.element),buttons:i.buttons,pointers:b.getActivePointerCount(),insideElementPressed:f.insideElementPressed,buttonDownAny:0!==i.buttons,isTouchEvent:"touch"===f.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),h===!1&&a.cancelEvent(c))}function hb(b,c,d){var e,f,g,h,i=(ob[b.hash],b.getActivePointersListByType(d[0].type)),j=d.length;for(e=0;j>e;e++)f=d[e],g=i.getById(f.id),g&&(g.captured?(g.insideElement=!1,g.lastPos=g.currentPos,g.lastTime=g.currentTime,g.currentPos=f.currentPos,g.currentTime=f.currentTime):fb(i,g),f=g),b.exitHandler&&(h=b.exitHandler({eventSource:b,pointerType:f.type,position:k(f.currentPos,b.element),buttons:i.buttons,pointers:b.getActivePointerCount(),insideElementPressed:g?g.insideElementPressed:!1,buttonDownAny:0!==i.buttons,isTouchEvent:"touch"===f.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),h===!1&&a.cancelEvent(c))}function ib(b,c,d,e){var f,g,h,i,j=ob[b.hash],m=b.getActivePointersListByType(d[0].type),n=d.length; +if("undefined"!=typeof c.buttons?m.buttons=c.buttons:a.Browser.vendor===a.BROWSERS.IE&&a.Browser.version<9?0===e?m.buttons+=1:1===e?m.buttons+=4:2===e?m.buttons+=2:3===e?m.buttons+=8:4===e?m.buttons+=16:5===e&&(m.buttons+=32):0===e?m.buttons|=1:1===e?m.buttons|=4:2===e?m.buttons|=2:3===e?m.buttons|=8:4===e?m.buttons|=16:5===e&&(m.buttons|=32),0!==e)return b.nonPrimaryPressHandler&&(f=b.nonPrimaryPressHandler({eventSource:b,pointerType:d[0].type,position:k(d[0].currentPos,b.element),button:e,buttons:m.buttons,isTouchEvent:"touch"===d[0].type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),f===!1&&a.cancelEvent(c)),!1;for(g=0;n>g;g++)h=d[g],i=m.getById(h.id),i?(i.captured=!0,i.insideElementPressed=!0,i.insideElement=!0,i.contactPos=h.currentPos,i.contactTime=h.currentTime,i.lastPos=i.currentPos,i.lastTime=i.currentTime,i.currentPos=h.currentPos,i.currentTime=h.currentTime,h=i):(h.captured=!0,h.insideElementPressed=!0,h.insideElement=!0,eb(m,h)),m.contacts++,(b.dragHandler||b.dragEndHandler||b.pinchHandler)&&a.MouseTracker.gesturePointVelocityTracker.addPoint(b,h),1===m.contacts?b.pressHandler&&(f=b.pressHandler({eventSource:b,pointerType:h.type,position:k(h.contactPos,b.element),buttons:m.buttons,isTouchEvent:"touch"===h.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),f===!1&&a.cancelEvent(c)):2===m.contacts&&b.pinchHandler&&"touch"===h.type&&(j.pinchGPoints=m.asArray(),j.lastPinchDist=j.currentPinchDist=j.pinchGPoints[0].currentPos.distanceTo(j.pinchGPoints[1].currentPos),j.lastPinchCenter=j.currentPinchCenter=l(j.pinchGPoints[0].currentPos,j.pinchGPoints[1].currentPos));return!0}function jb(b,c,d,e){var f,g,h,i,j,m,n,o=ob[b.hash],p=b.getActivePointersListByType(d[0].type),q=d.length,r=!1,s=!1;if("undefined"!=typeof c.buttons?p.buttons=c.buttons:a.Browser.vendor===a.BROWSERS.IE&&a.Browser.version<9?0===e?p.buttons-=1:1===e?p.buttons-=4:2===e?p.buttons-=2:3===e?p.buttons-=8:4===e?p.buttons-=16:5===e&&(p.buttons-=32):0===e?p.buttons^=-2:1===e?p.buttons^=-5:2===e?p.buttons^=-3:3===e?p.buttons^=-9:4===e?p.buttons^=-17:5===e&&(p.buttons^=-33),0!==e)return b.nonPrimaryReleaseHandler&&(f=b.nonPrimaryReleaseHandler({eventSource:b,pointerType:d[0].type,position:k(d[0].currentPos,b.element),button:e,buttons:p.buttons,isTouchEvent:"touch"===d[0].type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),f===!1&&a.cancelEvent(c)),!1;for(i=0;q>i;i++)j=d[i],m=p.getById(j.id),m&&(m.captured&&(m.captured=!1,r=!0,s=!0),m.lastPos=m.currentPos,m.lastTime=m.currentTime,m.currentPos=j.currentPos,m.currentTime=j.currentTime,m.insideElement||fb(p,m),g=m.currentPos,h=m.currentTime,s?(p.contacts--,(b.dragHandler||b.dragEndHandler||b.pinchHandler)&&a.MouseTracker.gesturePointVelocityTracker.removePoint(b,m),0===p.contacts?(b.releaseHandler&&(f=b.releaseHandler({eventSource:b,pointerType:m.type,position:k(g,b.element),buttons:p.buttons,insideElementPressed:m.insideElementPressed,insideElementReleased:m.insideElement,isTouchEvent:"touch"===m.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),f===!1&&a.cancelEvent(c)),b.dragEndHandler&&!m.currentPos.equals(m.contactPos)&&(f=b.dragEndHandler({eventSource:b,pointerType:m.type,position:k(m.currentPos,b.element),speed:m.speed,direction:m.direction,shift:c.shiftKey,isTouchEvent:"touch"===m.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),f===!1&&a.cancelEvent(c)),(b.clickHandler||b.dblClickHandler)&&m.insideElement&&(n=h-m.contactTime<=b.clickTimeThreshold&&m.contactPos.distanceTo(g)<=b.clickDistThreshold,b.clickHandler&&(f=b.clickHandler({eventSource:b,pointerType:m.type,position:k(m.currentPos,b.element),quick:n,shift:c.shiftKey,isTouchEvent:"touch"===m.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),f===!1&&a.cancelEvent(c)),b.dblClickHandler&&n&&(p.clicks++,1===p.clicks?(o.lastClickPos=g,o.dblClickTimeOut=setTimeout(function(){p.clicks=0},b.dblClickTimeThreshold)):2===p.clicks&&(clearTimeout(o.dblClickTimeOut),p.clicks=0,o.lastClickPos.distanceTo(g)<=b.dblClickDistThreshold&&(f=b.dblClickHandler({eventSource:b,pointerType:m.type,position:k(m.currentPos,b.element),shift:c.shiftKey,isTouchEvent:"touch"===m.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),f===!1&&a.cancelEvent(c)),o.lastClickPos=null)))):2===p.contacts&&b.pinchHandler&&"touch"===m.type&&(o.pinchGPoints=p.asArray(),o.lastPinchDist=o.currentPinchDist=o.pinchGPoints[0].currentPos.distanceTo(o.pinchGPoints[1].currentPos),o.lastPinchCenter=o.currentPinchCenter=l(o.pinchGPoints[0].currentPos,o.pinchGPoints[1].currentPos))):b.releaseHandler&&(f=b.releaseHandler({eventSource:b,pointerType:m.type,position:k(g,b.element),buttons:p.buttons,insideElementPressed:m.insideElementPressed,insideElementReleased:m.insideElement,isTouchEvent:"touch"===m.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),f===!1&&a.cancelEvent(c)));return r}function kb(b,c,d){var e,f,g,h,i,j,m=ob[b.hash],n=b.getActivePointersListByType(d[0].type),o=d.length;for("undefined"!=typeof c.buttons&&(n.buttons=c.buttons),e=0;o>e;e++)f=d[e],g=n.getById(f.id),g?(f.hasOwnProperty("isPrimary")&&(g.isPrimary=f.isPrimary),g.lastPos=g.currentPos,g.lastTime=g.currentTime,g.currentPos=f.currentPos,g.currentTime=f.currentTime):(f.captured=!1,f.insideElementPressed=!1,f.insideElement=!0,eb(n,f));b.stopHandler&&"mouse"===d[0].type&&(clearTimeout(b.stopTimeOut),b.stopTimeOut=setTimeout(function(){mb(b,c,d[0].type)},b.stopDelay)),0===n.contacts?b.moveHandler&&(j=b.moveHandler({eventSource:b,pointerType:d[0].type,position:k(d[0].currentPos,b.element),buttons:n.buttons,isTouchEvent:"touch"===d[0].type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),j===!1&&a.cancelEvent(c)):1===n.contacts?(b.moveHandler&&(g=n.asArray()[0],j=b.moveHandler({eventSource:b,pointerType:g.type,position:k(g.currentPos,b.element),buttons:n.buttons,isTouchEvent:"touch"===g.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),j===!1&&a.cancelEvent(c)),b.dragHandler&&(g=n.asArray()[0],i=g.currentPos.minus(g.lastPos),j=b.dragHandler({eventSource:b,pointerType:g.type,position:k(g.currentPos,b.element),buttons:n.buttons,delta:i,speed:g.speed,direction:g.direction,shift:c.shiftKey,isTouchEvent:"touch"===g.type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),j===!1&&a.cancelEvent(c))):2===n.contacts&&(b.moveHandler&&(h=n.asArray(),j=b.moveHandler({eventSource:b,pointerType:h[0].type,position:k(l(h[0].currentPos,h[1].currentPos),b.element),buttons:n.buttons,isTouchEvent:"touch"===h[0].type,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),j===!1&&a.cancelEvent(c)),b.pinchHandler&&"touch"===d[0].type&&(i=m.pinchGPoints[0].currentPos.distanceTo(m.pinchGPoints[1].currentPos),i!=m.currentPinchDist&&(m.lastPinchDist=m.currentPinchDist,m.currentPinchDist=i,m.lastPinchCenter=m.currentPinchCenter,m.currentPinchCenter=l(m.pinchGPoints[0].currentPos,m.pinchGPoints[1].currentPos),j=b.pinchHandler({eventSource:b,pointerType:"touch",gesturePoints:m.pinchGPoints,lastCenter:k(m.lastPinchCenter,b.element),center:k(m.currentPinchCenter,b.element),lastDistance:m.lastPinchDist,distance:m.currentPinchDist,shift:c.shiftKey,originalEvent:c,preventDefaultAction:!1,userData:b.userData}),j===!1&&a.cancelEvent(c))))}function lb(a,b,c){jb(a,b,c,0),hb(a,b,c)}function mb(a,b,c){a.stopHandler&&a.stopHandler({eventSource:a,pointerType:c,position:j(b,a.element),buttons:a.getActivePointersListByType(c).buttons,isTouchEvent:"touch"===c,originalEvent:b,preventDefaultAction:!1,userData:a.userData})}var nb=[],ob={};a.MouseTracker=function(b){nb.push(this);var c=arguments;a.isPlainObject(b)||(b={element:c[0],clickTimeThreshold:c[1],clickDistThreshold:c[2]}),this.hash=Math.random(),this.element=a.getElement(b.element),this.clickTimeThreshold=b.clickTimeThreshold||a.DEFAULT_SETTINGS.clickTimeThreshold,this.clickDistThreshold=b.clickDistThreshold||a.DEFAULT_SETTINGS.clickDistThreshold,this.dblClickTimeThreshold=b.dblClickTimeThreshold||a.DEFAULT_SETTINGS.dblClickTimeThreshold,this.dblClickDistThreshold=b.dblClickDistThreshold||a.DEFAULT_SETTINGS.dblClickDistThreshold,this.userData=b.userData||null,this.stopDelay=b.stopDelay||50,this.enterHandler=b.enterHandler||null,this.exitHandler=b.exitHandler||null,this.pressHandler=b.pressHandler||null,this.nonPrimaryPressHandler=b.nonPrimaryPressHandler||null,this.releaseHandler=b.releaseHandler||null,this.nonPrimaryReleaseHandler=b.nonPrimaryReleaseHandler||null,this.moveHandler=b.moveHandler||null,this.scrollHandler=b.scrollHandler||null,this.clickHandler=b.clickHandler||null,this.dblClickHandler=b.dblClickHandler||null,this.dragHandler=b.dragHandler||null,this.dragEndHandler=b.dragEndHandler||null,this.pinchHandler=b.pinchHandler||null,this.stopHandler=b.stopHandler||null,this.keyDownHandler=b.keyDownHandler||null,this.keyUpHandler=b.keyUpHandler||null,this.keyHandler=b.keyHandler||null,this.focusHandler=b.focusHandler||null,this.blurHandler=b.blurHandler||null;var d=this;ob[this.hash]={click:function(a){m(d,a)},dblclick:function(a){n(d,a)},keydown:function(a){o(d,a)},keyup:function(a){p(d,a)},keypress:function(a){q(d,a)},focus:function(a){r(d,a)},blur:function(a){s(d,a)},wheel:function(a){t(d,a)},mousewheel:function(a){u(d,a)},DOMMouseScroll:function(a){u(d,a)},MozMousePixelScroll:function(a){u(d,a)},mouseenter:function(a){x(d,a)},mouseleave:function(a){A(d,a)},mouseover:function(a){y(d,a)},mouseout:function(a){B(d,a)},mousedown:function(a){E(d,a)},mouseup:function(a){F(d,a)},mouseupcaptured:function(a){G(d,a)},mousemove:function(a){I(d,a)},mousemovecaptured:function(a){J(d,a)},touchstart:function(a){M(d,a)},touchend:function(a){N(d,a)},touchendcaptured:function(a){O(d,a)},touchmove:function(a){Q(d,a)},touchmovecaptured:function(a){R(d,a)},touchcancel:function(a){T(d,a)},gesturestart:function(a){U(d,a)},gesturechange:function(a){V(d,a)},pointerover:function(a){W(d,a)},MSPointerOver:function(a){W(d,a)},pointerout:function(a){X(d,a)},MSPointerOut:function(a){X(d,a)},pointerdown:function(a){Y(d,a)},MSPointerDown:function(a){Y(d,a)},pointerup:function(a){Z(d,a)},MSPointerUp:function(a){Z(d,a)},pointermove:function(a){ab(d,a)},MSPointerMove:function(a){ab(d,a)},pointercancel:function(a){db(d,a)},MSPointerCancel:function(a){db(d,a)},pointerupcaptured:function(a){$(d,a)},pointermovecaptured:function(a){bb(d,a)},tracking:!1,activePointersLists:[],lastClickPos:null,dblClickTimeOut:null,pinchGPoints:[],lastPinchDist:0,currentPinchDist:0,lastPinchCenter:null,currentPinchCenter:null},b.startDisabled||this.setTracking(!0)},a.MouseTracker.prototype={destroy:function(){var a;for(d(this),this.element=null,a=0;ac;c++)if(e.activePointersLists[c].type===b)return e.activePointersLists[c];return d=new a.MouseTracker.GesturePointList(b),e.activePointersLists.push(d),d},getActivePointerCount:function(){var a,b=ob[this.hash],c=b.activePointersLists.length,d=0;for(a=0;c>a;a++)d+=b.activePointersLists[a].getLength();return d},enterHandler:function(){},exitHandler:function(){},pressHandler:function(){},nonPrimaryPressHandler:function(){},releaseHandler:function(){},nonPrimaryReleaseHandler:function(){},moveHandler:function(){},scrollHandler:function(){},clickHandler:function(){},dblClickHandler:function(){},dragHandler:function(){},dragEndHandler:function(){},pinchHandler:function(){},stopHandler:function(){},keyDownHandler:function(){},keyUpHandler:function(){},keyHandler:function(){},focusHandler:function(){},blurHandler:function(){}},a.MouseTracker.gesturePointVelocityTracker=function(){var b=[],c=0,d=0,e=function(a,b){return a.hash.toString()+b.type+b.id.toString()},f=function(){var c,e,f,g,h,i,j=b.length,k=a.now();for(g=k-d,d=k,c=0;j>c;c++)e=b[c],f=e.gPoint,f.direction=Math.atan2(f.currentPos.y-e.lastPos.y,f.currentPos.x-e.lastPos.x),h=e.lastPos.distanceTo(f.currentPos),e.lastPos=f.currentPos,i=1e3*h/(g+1),f.speed=.75*i+.25*f.speed},g=function(g,h){var i=e(g,h);b.push({guid:i,gPoint:h,lastPos:h.currentPos}),1===b.length&&(d=a.now(),c=window.setInterval(f,50))},h=function(a,d){var f,g=e(a,d),h=b.length;for(f=0;h>f;f++)if(b[f].guid===g){b.splice(f,1),h--,0===h&&window.clearInterval(c);break}};return{addPoint:g,removePoint:h}}(),a.MouseTracker.captureElement=document,a.MouseTracker.wheelEventName=a.Browser.vendor==a.BROWSERS.IE&&a.Browser.version>8||"onwheel"in document.createElement("div")?"wheel":void 0!==document.onmousewheel?"mousewheel":"DOMMouseScroll",a.MouseTracker.supportsMouseCapture=function(){var b=document.createElement("div");return a.isFunction(b.setCapture)&&a.isFunction(b.releaseCapture)}(),a.MouseTracker.subscribeEvents=["click","dblclick","keydown","keyup","keypress","focus","blur",a.MouseTracker.wheelEventName],"DOMMouseScroll"==a.MouseTracker.wheelEventName&&a.MouseTracker.subscribeEvents.push("MozMousePixelScroll"),window.PointerEvent&&(window.navigator.pointerEnabled||a.Browser.vendor!==a.BROWSERS.IE)?(a.MouseTracker.havePointerEvents=!0,a.MouseTracker.subscribeEvents.push("pointerover","pointerout","pointerdown","pointerup","pointermove","pointercancel"),a.MouseTracker.unprefixedPointerEvents=!0,a.MouseTracker.maxTouchPoints=navigator.maxTouchPoints?navigator.maxTouchPoints:0,a.MouseTracker.haveMouseEnter=!1):window.MSPointerEvent&&window.navigator.msPointerEnabled?(a.MouseTracker.havePointerEvents=!0,a.MouseTracker.subscribeEvents.push("MSPointerOver","MSPointerOut","MSPointerDown","MSPointerUp","MSPointerMove","MSPointerCancel"),a.MouseTracker.unprefixedPointerEvents=!1,a.MouseTracker.maxTouchPoints=navigator.msMaxTouchPoints?navigator.msMaxTouchPoints:0,a.MouseTracker.haveMouseEnter=!1):(a.MouseTracker.havePointerEvents=!1,a.Browser.vendor===a.BROWSERS.IE&&a.Browser.version<9?(a.MouseTracker.subscribeEvents.push("mouseenter","mouseleave"),a.MouseTracker.haveMouseEnter=!0):(a.MouseTracker.subscribeEvents.push("mouseover","mouseout"),a.MouseTracker.haveMouseEnter=!1),a.MouseTracker.subscribeEvents.push("mousedown","mouseup","mousemove"),"ontouchstart"in window&&a.MouseTracker.subscribeEvents.push("touchstart","touchend","touchmove","touchcancel"),"ongesturestart"in window&&a.MouseTracker.subscribeEvents.push("gesturestart","gesturechange"),a.MouseTracker.mousePointerId="legacy-mouse",a.MouseTracker.maxTouchPoints=10),a.MouseTracker.GesturePointList=function(a){this._gPoints=[],this.type=a,this.buttons=0,this.contacts=0,this.clicks=0,this.captureCount=0},a.MouseTracker.GesturePointList.prototype={getLength:function(){return this._gPoints.length},asArray:function(){return this._gPoints},add:function(a){return this._gPoints.push(a)},removeById:function(a){var b,c=this._gPoints.length;for(b=0;c>b;b++)if(this._gPoints[b].id===a){this._gPoints.splice(b,1);break}return this._gPoints.length},getByIndex:function(a){return ab;b++)if(this._gPoints[b].id===a)return this._gPoints[b];return null},getPrimary:function(){var a,b=this._gPoints.length;for(a=0;b>a;a++)if(this._gPoints[a].isPrimary)return this._gPoints[a];return null}}}(OpenSeadragon),function(a){a.ControlAnchor={NONE:0,TOP_LEFT:1,TOP_RIGHT:2,BOTTOM_RIGHT:3,BOTTOM_LEFT:4,ABSOLUTE:5},a.Control=function(b,c,d){var e=b.parentNode;"number"==typeof c&&(a.console.error("Passing an anchor directly into the OpenSeadragon.Control constructor is deprecated; please use an options object instead. Support for this deprecated variant is scheduled for removal in December 2013"),c={anchor:c}),c.attachToViewer="undefined"==typeof c.attachToViewer?!0:c.attachToViewer,this.autoFade="undefined"==typeof c.autoFade?!0:c.autoFade,this.element=b,this.anchor=c.anchor,this.container=d,this.anchor==a.ControlAnchor.ABSOLUTE?(this.wrapper=a.makeNeutralElement("div"),this.wrapper.style.position="absolute",this.wrapper.style.top="number"==typeof c.top?c.top+"px":c.top,this.wrapper.style.left="number"==typeof c.left?c.left+"px":c.left,this.wrapper.style.height="number"==typeof c.height?c.height+"px":c.height,this.wrapper.style.width="number"==typeof c.width?c.width+"px":c.width,this.wrapper.style.margin="0px",this.wrapper.style.padding="0px",this.element.style.position="relative",this.element.style.top="0px",this.element.style.left="0px",this.element.style.height="100%",this.element.style.width="100%"):(this.wrapper=a.makeNeutralElement("div"),this.wrapper.style.display="inline-block",this.anchor==a.ControlAnchor.NONE&&(this.wrapper.style.width=this.wrapper.style.height="100%")),this.wrapper.appendChild(this.element),c.attachToViewer?this.anchor==a.ControlAnchor.TOP_RIGHT||this.anchor==a.ControlAnchor.BOTTOM_RIGHT?this.container.insertBefore(this.wrapper,this.container.firstChild):this.container.appendChild(this.wrapper):e.appendChild(this.wrapper)},a.Control.prototype={destroy:function(){this.wrapper.removeChild(this.element),this.container.removeChild(this.wrapper)},isVisible:function(){return"none"!=this.wrapper.style.display},setVisible:function(b){this.wrapper.style.display=b?this.anchor==a.ControlAnchor.ABSOLUTE?"block":"inline-block":"none"},setOpacity:function(b){this.element[a.SIGNAL]&&a.Browser.vendor==a.BROWSERS.IE?a.setElementOpacity(this.element,b,!0):a.setElementOpacity(this.wrapper,b,!0)}}}(OpenSeadragon),function(a){function b(a,b){var c,d=a.controls;for(c=d.length-1;c>=0;c--)if(d[c].element==b)return c;return-1}a.ControlDock=function(b){var c,d,e=["topleft","topright","bottomright","bottomleft"];for(a.extend(!0,this,{id:"controldock-"+a.now()+"-"+Math.floor(1e6*Math.random()),container:a.makeNeutralElement("div"),controls:[]},b),this.container.onsubmit=function(){return!1},this.element&&(this.element=a.getElement(this.element),this.element.appendChild(this.container),this.element.style.position="relative",this.container.style.width="100%",this.container.style.height="100%"),d=0;d=0)){switch(d.anchor){case a.ControlAnchor.TOP_RIGHT:e=this.controls.topright,c.style.position="relative",c.style.paddingRight="0px",c.style.paddingTop="0px";break;case a.ControlAnchor.BOTTOM_RIGHT:e=this.controls.bottomright,c.style.position="relative",c.style.paddingRight="0px",c.style.paddingBottom="0px";break;case a.ControlAnchor.BOTTOM_LEFT:e=this.controls.bottomleft,c.style.position="relative",c.style.paddingLeft="0px",c.style.paddingBottom="0px";break;case a.ControlAnchor.TOP_LEFT:e=this.controls.topleft,c.style.position="relative",c.style.paddingLeft="0px",c.style.paddingTop="0px";break;case a.ControlAnchor.ABSOLUTE:e=this.container,c.style.margin="0px",c.style.padding="0px";break;default:case a.ControlAnchor.NONE:e=this.container,c.style.margin="0px",c.style.padding="0px"}this.controls.push(new a.Control(c,d,e)),c.style.display="inline-block"}},removeControl:function(c){c=a.getElement(c);var d=b(this,c);return d>=0&&(this.controls[d].destroy(),this.controls.splice(d,1)),this},clearControls:function(){for(;this.controls.length>0;)this.controls.pop().destroy();return this},areControlsEnabled:function(){var a;for(a=this.controls.length-1;a>=0;a--)if(this.controls[a].isVisible())return!0;return!1},setControlsEnabled:function(a){var b;for(b=this.controls.length-1;b>=0;b--)this.controls[b].setVisible(a);return this}}}(OpenSeadragon),function($){function _getSafeElemSize(a){return a=$.getElement(a),new $.Point(0===a.clientWidth?1:a.clientWidth,0===a.clientHeight?1:a.clientHeight)}function getTileSourceImplementation(viewer,tileSource,successCallback,failCallback){var _this=viewer;"string"==$.type(tileSource)&&(tileSource.match(/\s*<.*/)?tileSource=$.parseXml(tileSource):tileSource.match(/\s*[\{\[].*/)&&(tileSource=eval("("+tileSource+")"))),setTimeout(function(){if("string"==$.type(tileSource))tileSource=new $.TileSource({url:tileSource,ajaxWithCredentials:viewer.ajaxWithCredentials,success:function(a){successCallback(a.tileSource)}}),tileSource.addHandler("open-failed",function(a){failCallback(a)});else if($.isPlainObject(tileSource)||tileSource.nodeType)if(void 0===tileSource.ajaxWithCredentials&&(tileSource.ajaxWithCredentials=viewer.ajaxWithCredentials),$.isFunction(tileSource.getTileUrl)){var a=new $.TileSource(tileSource);a.getTileUrl=tileSource.getTileUrl,successCallback(a)}else{var b=$.TileSource.determineType(_this,tileSource);if(!b)return void failCallback({message:"Unable to load TileSource",source:tileSource});var c=b.prototype.configure.apply(_this,[tileSource]),d=new b(c);successCallback(d)}else successCallback(tileSource)},1)}function getOverlayObject(a,b){if(b instanceof $.Overlay)return b;var c=null;if(b.element)c=$.getElement(b.element);else{var d=b.id?b.id:"openseadragon-overlay-"+Math.floor(1e7*Math.random());c=$.getElement(b.id),c||(c=document.createElement("a"),c.href="#/overlay/"+d),c.id=d,$.addClass(c,b.className?b.className:"openseadragon-overlay")}var e=b.location;e||(e=b.width&&b.height?void 0!==b.px?a.viewport.imageToViewportRectangle(new $.Rect(b.px,b.py,b.width,b.height)):new $.Rect(b.x,b.y,b.width,b.height):void 0!==b.px?a.viewport.imageToViewportCoordinates(new $.Point(b.px,b.py)):new $.Point(b.x,b.y));var f=b.placement;return f&&"string"===$.type(f)&&(f=$.OverlayPlacement[b.placement.toUpperCase()]),new $.Overlay({element:c,location:e,placement:f,onDraw:b.onDraw,checkResize:b.checkResize})}function getOverlayIndex(a,b){var c;for(c=a.length-1;c>=0;c--)if(a[c].element===b)return c;return-1}function scheduleUpdate(a,b){return $.requestAnimationFrame(function(){b(a)})}function scheduleControlsFade(a){$.requestAnimationFrame(function(){updateControlsFade(a)})}function beginControlsAutoHide(a){a.autoHideControls&&(a.controlsShouldFade=!0,a.controlsFadeBeginTime=$.now()+a.controlsFadeDelay,window.setTimeout(function(){scheduleControlsFade(a)},a.controlsFadeDelay))}function updateControlsFade(a){var b,c,d,e;if(a.controlsShouldFade){for(b=$.now(),c=b-a.controlsFadeBeginTime,d=1-c/a.controlsFadeLength,d=Math.min(1,d),d=Math.max(0,d),e=a.controls.length-1;e>=0;e--)a.controls[e].autoFade&&a.controls[e].setOpacity(d);d>0&&scheduleControlsFade(a)}}function abortControlsAutoHide(a){var b;for(a.controlsShouldFade=!1,b=a.controls.length-1;b>=0;b--)a.controls[b].setOpacity(1)}function onFocus(){abortControlsAutoHide(this)}function onBlur(){beginControlsAutoHide(this)}function onCanvasKeyDown(a){if(a.preventDefaultAction||a.ctrl||a.alt||a.meta)return!0;switch(a.keyCode){case 38:return a.shift?this.viewport.zoomBy(1.1):this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0,-40))),this.viewport.applyConstraints(),!1;case 40:return a.shift?this.viewport.zoomBy(.9):this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0,40))),this.viewport.applyConstraints(),!1;case 37:return this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(-40,0))),this.viewport.applyConstraints(),!1;case 39:return this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(40,0))),this.viewport.applyConstraints(),!1;default:return!0}}function onCanvasKeyPress(a){if(a.preventDefaultAction||a.ctrl||a.alt||a.meta)return!0;switch(a.keyCode){case 61:return this.viewport.zoomBy(1.1),this.viewport.applyConstraints(),!1;case 45:return this.viewport.zoomBy(.9),this.viewport.applyConstraints(),!1;case 48:return this.viewport.goHome(),this.viewport.applyConstraints(),!1;case 119:case 87:return a.shift?this.viewport.zoomBy(1.1):this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0,-40))),this.viewport.applyConstraints(),!1;case 115:case 83:return a.shift?this.viewport.zoomBy(.9):this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0,40))),this.viewport.applyConstraints(),!1;case 97:return this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(-40,0))),this.viewport.applyConstraints(),!1;case 100:return this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(40,0))),this.viewport.applyConstraints(),!1;default:return!0}}function onCanvasClick(a){var b,c=document.activeElement==this.canvas;c||this.canvas.focus(),!a.preventDefaultAction&&this.viewport&&a.quick&&(b=this.gestureSettingsByDeviceType(a.pointerType),b.clickToZoom&&(this.viewport.zoomBy(a.shift?1/this.zoomPerClick:this.zoomPerClick,this.viewport.pointFromPixel(a.position,!0)),this.viewport.applyConstraints())),this.raiseEvent("canvas-click",{tracker:a.eventSource,position:a.position,quick:a.quick,shift:a.shift,originalEvent:a.originalEvent})}function onCanvasDblClick(a){var b;!a.preventDefaultAction&&this.viewport&&(b=this.gestureSettingsByDeviceType(a.pointerType),b.dblClickToZoom&&(this.viewport.zoomBy(a.shift?1/this.zoomPerClick:this.zoomPerClick,this.viewport.pointFromPixel(a.position,!0)),this.viewport.applyConstraints())),this.raiseEvent("canvas-double-click",{tracker:a.eventSource,position:a.position,shift:a.shift,originalEvent:a.originalEvent})}function onCanvasDrag(a){var b;!a.preventDefaultAction&&this.viewport&&(b=this.gestureSettingsByDeviceType(a.pointerType),this.panHorizontal||(a.delta.x=0),this.panVertical||(a.delta.y=0),this.viewport.panBy(this.viewport.deltaPointsFromPixels(a.delta.negate()),b.flickEnabled),this.constrainDuringPan&&this.viewport.applyConstraints()),this.raiseEvent("canvas-drag",{tracker:a.eventSource,position:a.position,delta:a.delta,speed:a.speed,direction:a.direction,shift:a.shift,originalEvent:a.originalEvent})}function onCanvasDragEnd(a){var b;if(!a.preventDefaultAction&&this.viewport){if(b=this.gestureSettingsByDeviceType(a.pointerType),b.flickEnabled&&a.speed>=b.flickMinSpeed){var c=b.flickMomentum*a.speed*Math.cos(a.direction-Math.PI/180*this.viewport.degrees),d=b.flickMomentum*a.speed*Math.sin(a.direction-Math.PI/180*this.viewport.degrees),e=this.viewport.pixelFromPoint(this.viewport.getCenter(!0)),f=this.viewport.pointFromPixel(new $.Point(e.x-c,e.y-d));this.panHorizontal||(f.x=e.x),this.panVertical||(f.y=e.y),this.viewport.panTo(f,!1)}this.viewport.applyConstraints()}this.raiseEvent("canvas-drag-end",{tracker:a.eventSource,position:a.position,speed:a.speed,direction:a.direction,shift:a.shift,originalEvent:a.originalEvent})}function onCanvasEnter(a){this.raiseEvent("canvas-enter",{tracker:a.eventSource,pointerType:a.pointerType,position:a.position,buttons:a.buttons,pointers:a.pointers,insideElementPressed:a.insideElementPressed,buttonDownAny:a.buttonDownAny,originalEvent:a.originalEvent})}function onCanvasExit(a){this.raiseEvent("canvas-exit",{tracker:a.eventSource,pointerType:a.pointerType,position:a.position,buttons:a.buttons,pointers:a.pointers,insideElementPressed:a.insideElementPressed,buttonDownAny:a.buttonDownAny,originalEvent:a.originalEvent})}function onCanvasPress(a){this.raiseEvent("canvas-press",{tracker:a.eventSource,pointerType:a.pointerType,position:a.position,insideElementPressed:a.insideElementPressed,insideElementReleased:a.insideElementReleased,originalEvent:a.originalEvent})}function onCanvasRelease(a){this.raiseEvent("canvas-release",{tracker:a.eventSource,pointerType:a.pointerType,position:a.position,insideElementPressed:a.insideElementPressed,insideElementReleased:a.insideElementReleased,originalEvent:a.originalEvent})}function onCanvasNonPrimaryPress(a){this.raiseEvent("canvas-nonprimary-press",{tracker:a.eventSource,position:a.position,pointerType:a.pointerType,button:a.button,buttons:a.buttons,originalEvent:a.originalEvent})}function onCanvasNonPrimaryRelease(a){this.raiseEvent("canvas-nonprimary-release",{tracker:a.eventSource,position:a.position,pointerType:a.pointerType,button:a.button,buttons:a.buttons,originalEvent:a.originalEvent})}function onCanvasPinch(a){var b,c,d,e;if(!a.preventDefaultAction&&this.viewport&&(b=this.gestureSettingsByDeviceType(a.pointerType),b.pinchToZoom&&(c=this.viewport.pointFromPixel(a.center,!0),d=this.viewport.pointFromPixel(a.lastCenter,!0),e=d.minus(c),this.panHorizontal||(e.x=0),this.panVertical||(e.y=0),this.viewport.zoomBy(a.distance/a.lastDistance,c,!0),this.viewport.panBy(e,!0),this.viewport.applyConstraints()),b.pinchRotate)){var f=Math.atan2(a.gesturePoints[0].currentPos.y-a.gesturePoints[1].currentPos.y,a.gesturePoints[0].currentPos.x-a.gesturePoints[1].currentPos.x),g=Math.atan2(a.gesturePoints[0].lastPos.y-a.gesturePoints[1].lastPos.y,a.gesturePoints[0].lastPos.x-a.gesturePoints[1].lastPos.x);this.viewport.setRotation(this.viewport.getRotation()+(f-g)*(180/Math.PI))}return this.raiseEvent("canvas-pinch",{tracker:a.eventSource,gesturePoints:a.gesturePoints,lastCenter:a.lastCenter,center:a.center,lastDistance:a.lastDistance,distance:a.distance,shift:a.shift,originalEvent:a.originalEvent}),!1}function onCanvasScroll(a){var b,c;return!a.preventDefaultAction&&this.viewport&&(b=this.gestureSettingsByDeviceType(a.pointerType),b.scrollToZoom&&(c=Math.pow(this.zoomPerScroll,a.scroll),this.viewport.zoomBy(c,this.viewport.pointFromPixel(a.position,!0)),this.viewport.applyConstraints())),this.raiseEvent("canvas-scroll",{tracker:a.eventSource,position:a.position,scroll:a.scroll,shift:a.shift,originalEvent:a.originalEvent}),b&&b.scrollToZoom?!1:void 0}function onContainerEnter(a){THIS[this.hash].mouseInside=!0,abortControlsAutoHide(this),this.raiseEvent("container-enter",{tracker:a.eventSource,position:a.position,buttons:a.buttons,pointers:a.pointers,insideElementPressed:a.insideElementPressed,buttonDownAny:a.buttonDownAny,originalEvent:a.originalEvent})}function onContainerExit(a){a.pointers<1&&(THIS[this.hash].mouseInside=!1,THIS[this.hash].animating||beginControlsAutoHide(this)),this.raiseEvent("container-exit",{tracker:a.eventSource,position:a.position,buttons:a.buttons,pointers:a.pointers,insideElementPressed:a.insideElementPressed,buttonDownAny:a.buttonDownAny,originalEvent:a.originalEvent})}function updateMulti(a){updateOnce(a),a._updateRequestId=a.isOpen()?scheduleUpdate(a,updateMulti):!1}function updateOnce(a){if(!a._opening){if(a.autoResize){var b=_getSafeElemSize(a.container);if(!b.equals(THIS[a.hash].prevContainerSize)){var c=a.viewport.getBounds(),d=a.viewport.getCenter();resizeViewportAndRecenter(a,b,c,d),THIS[a.hash].prevContainerSize=b,THIS[a.hash].forceRedraw=!0}}var e=a.viewport.update(),f=a.world.update()||e;e&&a.raiseEvent("viewport-change"),a.referenceStrip&&(f=a.referenceStrip.update(a.viewport)||f),!THIS[a.hash].animating&&f&&(a.raiseEvent("animation-start"),abortControlsAutoHide(a)),(f||THIS[a.hash].forceRedraw||a.world.needsDraw())&&(drawWorld(a),a._drawOverlays(),a.navigator&&a.navigator.update(a.viewport),THIS[a.hash].forceRedraw=!1,f&&a.raiseEvent("animation")),THIS[a.hash].animating&&!f&&(a.raiseEvent("animation-finish"),THIS[a.hash].mouseInside||beginControlsAutoHide(a)),THIS[a.hash].animating=f}}function resizeViewportAndRecenter(a,b,c,d){var e=a.viewport;e.resize(b,!0);var f=a.world.getHomeBounds(),g=c.width<=f.width?c.width:f.width,h=c.height<=f.height?c.height:f.height,i=new $.Rect(d.x-g/2,d.y-h/2,g,h);e.fitBounds(i,!0)}function drawWorld(a){a.imageLoader.clear(),a.drawer.clear(),a.world.draw(),a.raiseEvent("update-viewport",{})}function resolveUrl(a,b){return a?a+b:b}function beginZoomingIn(){THIS[this.hash].lastZoomTime=$.now(),THIS[this.hash].zoomFactor=this.zoomPerSecond,THIS[this.hash].zooming=!0,scheduleZoom(this) +}function beginZoomingOut(){THIS[this.hash].lastZoomTime=$.now(),THIS[this.hash].zoomFactor=1/this.zoomPerSecond,THIS[this.hash].zooming=!0,scheduleZoom(this)}function endZooming(){THIS[this.hash].zooming=!1}function scheduleZoom(a){$.requestAnimationFrame($.delegate(a,doZoom))}function doZoom(){var a,b,c;THIS[this.hash].zooming&&this.viewport&&(a=$.now(),b=a-THIS[this.hash].lastZoomTime,c=Math.pow(THIS[this.hash].zoomFactor,b/1e3),this.viewport.zoomBy(c),this.viewport.applyConstraints(),THIS[this.hash].lastZoomTime=a,scheduleZoom(this))}function doSingleZoomIn(){this.viewport&&(THIS[this.hash].zooming=!1,this.viewport.zoomBy(this.zoomPerClick/1),this.viewport.applyConstraints())}function doSingleZoomOut(){this.viewport&&(THIS[this.hash].zooming=!1,this.viewport.zoomBy(1/this.zoomPerClick),this.viewport.applyConstraints())}function lightUp(){this.buttons.emulateEnter(),this.buttons.emulateExit()}function onHome(){this.viewport&&this.viewport.goHome()}function onFullScreen(){this.isFullPage()&&!$.isFullScreen()?this.setFullPage(!1):this.setFullScreen(!this.isFullPage()),this.buttons&&this.buttons.emulateExit(),this.fullPageButton.element.focus(),this.viewport&&this.viewport.applyConstraints()}function onRotateLeft(){if(this.viewport){var a=this.viewport.getRotation();0===a?a=270:a-=90,this.viewport.setRotation(a)}}function onRotateRight(){if(this.viewport){var a=this.viewport.getRotation();270===a?a=0:a+=90,this.viewport.setRotation(a)}}function onPrevious(){var a=this._sequenceIndex-1;this.navPrevNextWrap&&0>a&&(a+=this.tileSources.length),this.goToPage(a)}function onNext(){var a=this._sequenceIndex+1;this.navPrevNextWrap&&a>=this.tileSources.length&&(a=0),this.goToPage(a)}var THIS={},nextHash=1;$.Viewer=function(a){var b,c=arguments,d=this;if($.isPlainObject(a)||(a={id:c[0],xmlPath:c.length>1?c[1]:void 0,prefixUrl:c.length>2?c[2]:void 0,controls:c.length>3?c[3]:void 0,overlays:c.length>4?c[4]:void 0}),a.config&&($.extend(!0,a,a.config),delete a.config),$.extend(!0,this,{id:a.id,hash:a.hash||nextHash++,element:null,container:null,canvas:null,overlays:[],overlaysContainer:null,previousBody:[],customControls:[],source:null,drawer:null,world:null,viewport:null,navigator:null,collectionViewport:null,collectionDrawer:null,navImages:null,buttons:null,profiler:null},$.DEFAULT_SETTINGS,a),"undefined"==typeof this.hash)throw new Error("A hash must be defined, either by specifying options.id or options.hash.");for("undefined"!=typeof THIS[this.hash]&&$.console.warn("Hash "+this.hash+" has already been used."),THIS[this.hash]={fsBoundsDelta:new $.Point(1,1),prevContainerSize:null,animating:!1,forceRedraw:!1,mouseInside:!1,group:null,zooming:!1,zoomFactor:null,lastZoomTime:null,fullPage:!1,onfullscreenchange:null},this._sequenceIndex=0,this._firstOpen=!0,this._updateRequestId=null,this._loadQueue=[],this.currentOverlays=[],$.EventSource.call(this),this.addHandler("open-failed",function(a){var b=$.getString("Errors.OpenFailed",a.eventSource,a.message);d._showMessage(b)}),$.ControlDock.call(this,a),this.xmlPath&&(this.tileSources=[this.xmlPath]),this.element=this.element||document.getElementById(this.id),this.canvas=$.makeNeutralElement("div"),this.canvas.className="openseadragon-canvas",function(a){a.width="100%",a.height="100%",a.overflow="hidden",a.position="absolute",a.top="0px",a.left="0px"}(this.canvas.style),$.setElementTouchActionNone(this.canvas),this.canvas.tabIndex=a.tabIndex||0,this.container.className="openseadragon-container",function(a){a.width="100%",a.height="100%",a.position="relative",a.overflow="hidden",a.left="0px",a.top="0px",a.textAlign="left"}(this.container.style),this.container.insertBefore(this.canvas,this.container.firstChild),this.element.appendChild(this.container),this.bodyWidth=document.body.style.width,this.bodyHeight=document.body.style.height,this.bodyOverflow=document.body.style.overflow,this.docOverflow=document.documentElement.style.overflow,this.innerTracker=new $.MouseTracker({element:this.canvas,startDisabled:this.mouseNavEnabled?!1:!0,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,dblClickTimeThreshold:this.dblClickTimeThreshold,dblClickDistThreshold:this.dblClickDistThreshold,keyDownHandler:$.delegate(this,onCanvasKeyDown),keyHandler:$.delegate(this,onCanvasKeyPress),clickHandler:$.delegate(this,onCanvasClick),dblClickHandler:$.delegate(this,onCanvasDblClick),dragHandler:$.delegate(this,onCanvasDrag),dragEndHandler:$.delegate(this,onCanvasDragEnd),enterHandler:$.delegate(this,onCanvasEnter),exitHandler:$.delegate(this,onCanvasExit),pressHandler:$.delegate(this,onCanvasPress),releaseHandler:$.delegate(this,onCanvasRelease),nonPrimaryPressHandler:$.delegate(this,onCanvasNonPrimaryPress),nonPrimaryReleaseHandler:$.delegate(this,onCanvasNonPrimaryRelease),scrollHandler:$.delegate(this,onCanvasScroll),pinchHandler:$.delegate(this,onCanvasPinch)}),this.outerTracker=new $.MouseTracker({element:this.container,startDisabled:this.mouseNavEnabled?!1:!0,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,dblClickTimeThreshold:this.dblClickTimeThreshold,dblClickDistThreshold:this.dblClickDistThreshold,enterHandler:$.delegate(this,onContainerEnter),exitHandler:$.delegate(this,onContainerExit)}),this.toolbar&&(this.toolbar=new $.ControlDock({element:this.toolbar})),this.bindStandardControls(),THIS[this.hash].prevContainerSize=_getSafeElemSize(this.container),this.world=new $.World({viewer:this}),this.world.addHandler("add-item",function(){d.source=d.world.getItemAt(0).source,THIS[d.hash].forceRedraw=!0,d._updateRequestId||(d._updateRequestId=scheduleUpdate(d,updateMulti))}),this.world.addHandler("remove-item",function(){d.source=d.world.getItemCount()?d.world.getItemAt(0).source:null,THIS[d.hash].forceRedraw=!0}),this.world.addHandler("metrics-change",function(){d.viewport&&d.viewport.setHomeBounds(d.world.getHomeBounds(),d.world.getContentFactor())}),this.world.addHandler("item-index-change",function(){d.source=d.world.getItemAt(0).source}),this.viewport=new $.Viewport({containerSize:THIS[this.hash].prevContainerSize,springStiffness:this.springStiffness,animationTime:this.animationTime,minZoomImageRatio:this.minZoomImageRatio,maxZoomPixelRatio:this.maxZoomPixelRatio,visibilityRatio:this.visibilityRatio,wrapHorizontal:this.wrapHorizontal,wrapVertical:this.wrapVertical,defaultZoomLevel:this.defaultZoomLevel,minZoomLevel:this.minZoomLevel,maxZoomLevel:this.maxZoomLevel,viewer:this,degrees:this.degrees,navigatorRotate:this.navigatorRotate,homeFillsViewer:this.homeFillsViewer,margins:this.viewportMargins}),this.viewport.setHomeBounds(this.world.getHomeBounds(),this.world.getContentFactor()),this.imageLoader=new $.ImageLoader({jobLimit:this.imageLoaderLimit}),this.tileCache=new $.TileCache({maxImageCacheCount:this.maxImageCacheCount}),this.drawer=new $.Drawer({viewer:this,viewport:this.viewport,element:this.canvas,debugGridColor:this.debugGridColor}),this.overlaysContainer=$.makeNeutralElement("div"),this.canvas.appendChild(this.overlaysContainer),this.drawer.canRotate()||(this.rotateLeft&&(b=this.buttons.buttons.indexOf(this.rotateLeft),this.buttons.buttons.splice(b,1),this.buttons.element.removeChild(this.rotateLeft.element)),this.rotateRight&&(b=this.buttons.buttons.indexOf(this.rotateRight),this.buttons.buttons.splice(b,1),this.buttons.element.removeChild(this.rotateRight.element))),this.showNavigator&&(this.navigator=new $.Navigator({id:this.navigatorId,position:this.navigatorPosition,sizeRatio:this.navigatorSizeRatio,maintainSizeRatio:this.navigatorMaintainSizeRatio,top:this.navigatorTop,left:this.navigatorLeft,width:this.navigatorWidth,height:this.navigatorHeight,autoResize:this.navigatorAutoResize,prefixUrl:this.prefixUrl,viewer:this,navigatorRotate:this.navigatorRotate,crossOriginPolicy:this.crossOriginPolicy})),this.sequenceMode&&this.bindSequenceControls(),this.tileSources&&this.open(this.tileSources),b=0;bc;c++)this.previousBody.push(d.childNodes[0]),d.removeChild(d.childNodes[0]);this.toolbar&&this.toolbar.element&&(this.toolbar.parentNode=this.toolbar.element.parentNode,this.toolbar.nextSibling=this.toolbar.element.nextSibling,d.appendChild(this.toolbar.element),$.addClass(this.toolbar.element,"fullpage")),$.addClass(this.element,"fullpage"),d.appendChild(this.element),this.element.style.height=$.getWindowSize().y+"px",this.element.style.width=$.getWindowSize().x+"px",this.toolbar&&this.toolbar.element&&(this.element.style.height=$.getElementSize(this.element).y-$.getElementSize(this.toolbar.element).y+"px"),THIS[this.hash].fullPage=!0,$.delegate(this,onContainerEnter)({})}else{for(this.element.style.margin=this.elementMargin,this.element.style.padding=this.elementPadding,e.margin=this.bodyMargin,f.margin=this.docMargin,e.padding=this.bodyPadding,f.padding=this.docPadding,e.width=this.bodyWidth,e.height=this.bodyHeight,d.removeChild(this.element),b=this.previousBody.length,c=0;b>c;c++)d.appendChild(this.previousBody.shift());$.removeClass(this.element,"fullpage"),THIS[this.hash].prevElementParent.insertBefore(this.element,THIS[this.hash].prevNextSibling),this.toolbar&&this.toolbar.element&&(d.removeChild(this.toolbar.element),$.removeClass(this.toolbar.element,"fullpage"),this.toolbar.parentNode.insertBefore(this.toolbar.element,this.toolbar.nextSibling),delete this.toolbar.parentNode,delete this.toolbar.nextSibling),this.element.style.width=THIS[this.hash].prevElementWidth,this.element.style.height=THIS[this.hash].prevElementHeight;var i=0,j=function(){$.setPageScroll(g.pageScroll);var a=$.getPageScroll();i++,(10>i&&a.x!==g.pageScroll.x||a.y!==g.pageScroll.y)&&$.requestAnimationFrame(j)};$.requestAnimationFrame(j),THIS[this.hash].fullPage=!1,$.delegate(this,onContainerExit)({})}return this.navigator&&this.viewport&&this.navigator.update(this.viewport),this.raiseEvent("full-page",{fullPage:a}),this},setFullScreen:function(a){var b=this;if(!$.supportsFullScreen)return this.setFullPage(a);if($.isFullScreen()===a)return this;var c={fullScreen:a,preventDefaultAction:!1};if(this.raiseEvent("pre-full-screen",c),c.preventDefaultAction)return this;if(a){if(this.setFullPage(!0),!this.isFullPage())return this;this.fullPageStyleWidth=this.element.style.width,this.fullPageStyleHeight=this.element.style.height,this.element.style.width="100%",this.element.style.height="100%";var d=function(){var a=$.isFullScreen();a||($.removeEvent(document,$.fullScreenEventName,d),$.removeEvent(document,$.fullScreenErrorEventName,d),b.setFullPage(!1),b.isFullPage()&&(b.element.style.width=b.fullPageStyleWidth,b.element.style.height=b.fullPageStyleHeight)),b.navigator&&b.viewport&&b.navigator.update(b.viewport),b.raiseEvent("full-screen",{fullScreen:a})};$.addEvent(document,$.fullScreenEventName,d),$.addEvent(document,$.fullScreenErrorEventName,d),$.requestFullScreen(document.body)}else $.exitFullScreen();return this},isVisible:function(){return"hidden"!=this.container.style.visibility},setVisible:function(a){return this.container.style.visibility=a?"":"hidden",this.raiseEvent("visible",{visible:a}),this},addTiledImage:function(a){function b(b){for(var e=0;e=0&&a=0)return this;var f=getOverlayObject(this,e);return this.currentOverlays.push(f),f.drawHTML(this.overlaysContainer,this.viewport),this.raiseEvent("add-overlay",{element:a,location:e.location,placement:e.placement}),this},updateOverlay:function(a,b,c){var d;return a=$.getElement(a),d=getOverlayIndex(this.currentOverlays,a),d>=0&&(this.currentOverlays[d].update(b,c),THIS[this.hash].forceRedraw=!0,this.raiseEvent("update-overlay",{element:a,location:b,placement:c})),this},removeOverlay:function(a){var b;return a=$.getElement(a),b=getOverlayIndex(this.currentOverlays,a),b>=0&&(this.currentOverlays[b].destroy(),this.currentOverlays.splice(b,1),THIS[this.hash].forceRedraw=!0,this.raiseEvent("remove-overlay",{element:a})),this},clearOverlays:function(){for(;this.currentOverlays.length>0;)this.currentOverlays.pop().destroy();return THIS[this.hash].forceRedraw=!0,this.raiseEvent("clear-overlay",{}),this},_updateSequenceButtons:function(a){this.nextButton&&(this.tileSources&&this.tileSources.length-1!==a?this.nextButton.enable():this.navPrevNextWrap||this.nextButton.disable()),this.previousButton&&(a>0?this.previousButton.enable():this.navPrevNextWrap||this.previousButton.disable())},_showMessage:function(a){this._hideMessage();var b=$.makeNeutralElement("div");b.appendChild(document.createTextNode(a)),this.messageDiv=$.makeCenteredNode(b),$.addClass(this.messageDiv,"openseadragon-message"),this.container.appendChild(this.messageDiv)},_hideMessage:function(){var a=this.messageDiv;a&&(a.parentNode.removeChild(a),delete this.messageDiv)},gestureSettingsByDeviceType:function(a){switch(a){case"mouse":return this.gestureSettingsMouse;case"touch":return this.gestureSettingsTouch;case"pen":return this.gestureSettingsPen;default:return this.gestureSettingsUnknown}},_drawOverlays:function(){var a,b=this.currentOverlays.length;for(a=0;b>a;a++)this.currentOverlays[a].drawHTML(this.overlaysContainer,this.viewport)}})}(OpenSeadragon),function(a){function b(a){a.quick&&this.viewer.viewport&&(this.viewer.viewport.panTo(this.viewport.pointFromPixel(a.position).rotate(-this.viewer.viewport.degrees,this.viewer.viewport.getHomeBounds().getCenter())),this.viewer.viewport.applyConstraints())}function c(a){this.viewer.viewport&&(this.panHorizontal||(a.delta.x=0),this.panVertical||(a.delta.y=0),this.viewer.viewport.panBy(this.viewport.deltaPointsFromPixels(a.delta)))}function d(a){a.insideElementPressed&&this.viewer.viewport&&this.viewer.viewport.applyConstraints()}function e(a){return this.viewer.raiseEvent("navigator-scroll",{tracker:a.eventSource,position:a.position,scroll:a.scroll,shift:a.shift,originalEvent:a.originalEvent}),!1}function f(a,b){a.style.webkitTransform="rotate("+b+"deg)",a.style.mozTransform="rotate("+b+"deg)",a.style.msTransform="rotate("+b+"deg)",a.style.oTransform="rotate("+b+"deg)",a.style.transform="rotate("+b+"deg)"}a.Navigator=function(g){var h,i,j=g.viewer,k=this;g.id?(this.element=document.getElementById(g.id),g.controlOptions={anchor:a.ControlAnchor.NONE,attachToViewer:!1,autoFade:!1}):(g.id="navigator-"+a.now(),this.element=a.makeNeutralElement("div"),g.controlOptions={anchor:a.ControlAnchor.TOP_RIGHT,attachToViewer:!0,autoFade:!0},g.position&&("BOTTOM_RIGHT"==g.position?g.controlOptions.anchor=a.ControlAnchor.BOTTOM_RIGHT:"BOTTOM_LEFT"==g.position?g.controlOptions.anchor=a.ControlAnchor.BOTTOM_LEFT:"TOP_RIGHT"==g.position?g.controlOptions.anchor=a.ControlAnchor.TOP_RIGHT:"TOP_LEFT"==g.position?g.controlOptions.anchor=a.ControlAnchor.TOP_LEFT:"ABSOLUTE"==g.position&&(g.controlOptions.anchor=a.ControlAnchor.ABSOLUTE,g.controlOptions.top=g.top,g.controlOptions.left=g.left,g.controlOptions.height=g.height,g.controlOptions.width=g.width))),this.element.id=g.id,this.element.className+=" navigator",g=a.extend(!0,{sizeRatio:a.DEFAULT_SETTINGS.navigatorSizeRatio},g,{element:this.element,tabIndex:-1,showNavigator:!1,mouseNavEnabled:!1,showNavigationControl:!1,showSequenceControl:!1,immediateRender:!0,blendTime:0,animationTime:0,autoResize:g.autoResize}),g.minPixelRatio=this.minPixelRatio=j.minPixelRatio,a.setElementTouchActionNone(this.element),this.borderWidth=2,this.fudge=new a.Point(1,1),this.totalBorderWidths=new a.Point(2*this.borderWidth,2*this.borderWidth).minus(this.fudge),g.controlOptions.anchor!=a.ControlAnchor.NONE&&!function(a,b){a.margin="0px",a.border=b+"px solid #555",a.padding="0px",a.background="#000",a.opacity=.8,a.overflow="hidden"}(this.element.style,this.borderWidth),this.displayRegion=a.makeNeutralElement("div"),this.displayRegion.id=this.element.id+"-displayregion",this.displayRegion.className="displayregion",function(a,b){a.position="relative",a.top="0px",a.left="0px",a.fontSize="0px",a.overflow="hidden",a.border=b+"px solid #900",a.margin="0px",a.padding="0px",a.background="transparent",a["float"]="left",a.cssFloat="left",a.styleFloat="left",a.zIndex=999999999,a.cursor="default"}(this.displayRegion.style,this.borderWidth),this.displayRegionContainer=a.makeNeutralElement("div"),this.displayRegionContainer.id=this.element.id+"-displayregioncontainer",this.displayRegionContainer.className="displayregioncontainer",this.displayRegionContainer.style.width="100%",this.displayRegionContainer.style.height="100%",j.addControl(this.element,g.controlOptions),this._resizeWithViewer=g.controlOptions.anchor!=a.ControlAnchor.ABSOLUTE&&g.controlOptions.anchor!=a.ControlAnchor.NONE,this._resizeWithViewer&&(g.width&&g.height?(this.element.style.height="number"==typeof g.height?g.height+"px":g.height,this.element.style.width="number"==typeof g.width?g.width+"px":g.width):(h=a.getElementSize(j.element),this.element.style.height=Math.round(h.y*g.sizeRatio)+"px",this.element.style.width=Math.round(h.x*g.sizeRatio)+"px",this.oldViewerSize=h),i=a.getElementSize(this.element),this.elementArea=i.x*i.y),this.oldContainerSize=new a.Point(0,0),a.Viewer.apply(this,[g]),this.displayRegionContainer.appendChild(this.displayRegion),this.element.getElementsByTagName("div")[0].appendChild(this.displayRegionContainer),g.navigatorRotate&&g.viewer.addHandler("rotate",function(a){f(k.displayRegionContainer,a.degrees),f(k.displayRegion,-a.degrees),k.viewport.setRotation(a.degrees)}),this.innerTracker.destroy(),this.innerTracker=new a.MouseTracker({element:this.element,dragHandler:a.delegate(this,c),clickHandler:a.delegate(this,b),releaseHandler:a.delegate(this,d),scrollHandler:a.delegate(this,e)}),this.addHandler("reset-size",function(){k.viewport&&k.viewport.goHome(!0)}),this.addHandler("reset-size",function(){k.viewport&&k.viewport.goHome(!0)}),j.world.addHandler("item-index-change",function(a){var b=k.world.getItemAt(a.previousIndex);k.world.setItemIndex(b,a.newIndex)}),j.world.addHandler("remove-item",function(a){var b=a.item,c=k._getMatchingItem(b); +c&&k.world.removeItem(c)}),this.update(j.viewport)},a.extend(a.Navigator.prototype,a.EventSource.prototype,a.Viewer.prototype,{updateSize:function(){if(this.viewport){var b=new a.Point(0===this.container.clientWidth?1:this.container.clientWidth,0===this.container.clientHeight?1:this.container.clientHeight);b.equals(this.oldContainerSize)||(this.viewport.resize(b,!0),this.viewport.goHome(!0),this.oldContainerSize=b,this.drawer.clear(),this.world.draw())}},update:function(b){var c,d,e,f,g,h;if(c=a.getElementSize(this.viewer.element),this._resizeWithViewer&&c.x&&c.y&&!c.equals(this.oldViewerSize)&&(this.oldViewerSize=c,this.maintainSizeRatio||!this.elementArea?(d=c.x*this.sizeRatio,e=c.y*this.sizeRatio):(d=Math.sqrt(this.elementArea*(c.x/c.y)),e=this.elementArea/d),this.element.style.width=Math.round(d)+"px",this.element.style.height=Math.round(e)+"px",this.elementArea||(this.elementArea=d*e),this.updateSize()),b&&this.viewport){f=b.getBounds(!0),g=this.viewport.pixelFromPoint(f.getTopLeft(),!1),h=this.viewport.pixelFromPoint(f.getBottomRight(),!1).minus(this.totalBorderWidths);var i=this.displayRegion.style;i.display=this.world.getItemCount()?"block":"none",i.top=Math.round(g.y)+"px",i.left=Math.round(g.x)+"px";var j=Math.abs(g.x-h.x),k=Math.abs(g.y-h.y);i.width=Math.round(Math.max(j,0))+"px",i.height=Math.round(Math.max(k,0))+"px"}},addTiledImage:function(b){var c=this,d=b.originalTiledImage;delete b.original;var e=a.extend({},b,{success:function(a){var b=a.item;b._originalForNavigator=d,c._matchBounds(b,d,!0),d.addHandler("bounds-change",function(){c._matchBounds(b,d)})}});return a.Viewer.prototype.addTiledImage.apply(this,[e])},_getMatchingItem:function(a){for(var b,c=this.world.getItemCount(),d=0;c>d;d++)if(b=this.world.getItemAt(d),b._originalForNavigator===a)return b;return null},_matchBounds:function(a,b,c){var d=b.getBounds();a.setPosition(d.getTopLeft(),c),a.setWidth(d.width,c)}})}(OpenSeadragon),function(a){var b={Errors:{Dzc:"Sorry, we don't support Deep Zoom Collections!",Dzi:"Hmm, this doesn't appear to be a valid Deep Zoom Image.",Xml:"Hmm, this doesn't appear to be a valid Deep Zoom Image.",ImageFormat:"Sorry, we don't support {0}-based Deep Zoom Images.",Security:"It looks like a security restriction stopped us from loading this Deep Zoom Image.",Status:"This space unintentionally left blank ({0} {1}).",OpenFailed:"Unable to open {0}: {1}"},Tooltips:{FullPage:"Toggle full page",Home:"Go home",ZoomIn:"Zoom in",ZoomOut:"Zoom out",NextPage:"Next page",PreviousPage:"Previous page",RotateLeft:"Rotate left",RotateRight:"Rotate right"}};a.extend(a,{getString:function(c){var d,e=c.split("."),f=null,g=arguments,h=b;for(d=0;d=c));b++);return Math.max(0,b-1)},getTileAtPoint:function(a,b){var c=b.times(this.dimensions.x).times(this.getLevelScale(a)),d=Math.floor(c.x/this.getTileSize(a)),e=Math.floor(c.y/this.getTileSize(a));return new $.Point(d,e)},getTileBounds:function(a,b,c){var d=this.dimensions.times(this.getLevelScale(a)),e=this.getTileSize(a),f=0===b?0:e*b-this.tileOverlap,g=0===c?0:e*c-this.tileOverlap,h=e+(0===b?1:2)*this.tileOverlap,i=e+(0===c?1:2)*this.tileOverlap,j=1/d.x;return h=Math.min(h,d.x-f),i=Math.min(i,d.y-g),new $.Rect(f*j,g*j,h*j,i*j)},getImageInfo:function(a){var b,c,d,e,f,g,h,i=this;a&&(f=a.split("/"),g=f[f.length-1],h=g.lastIndexOf("."),h>-1&&(f[f.length-1]=g.slice(0,h))),c=function(b){"string"==typeof b&&(b=$.parseXml(b));var c=$.TileSource.determineType(i,b,a);return c?(e=c.prototype.configure.apply(i,[b,a]),void 0===e.ajaxWithCredentials&&(e.ajaxWithCredentials=i.ajaxWithCredentials),d=new c(e),i.ready=!0,void i.raiseEvent("ready",{tileSource:d})):void i.raiseEvent("open-failed",{message:"Unable to load TileSource",source:a})},a.match(/\.js$/)?(b=a.split("/").pop().replace(".js",""),$.jsonp({url:a,async:!1,callbackName:b,callback:c})):$.makeAjaxRequest({url:a,withCredentials:this.ajaxWithCredentials,success:function(a){var b=processResponse(a);c(b)},error:function(b,c){var d;try{d="HTTP "+b.status+" attempting to load TileSource"}catch(e){var f;f="undefined"!=typeof c&&c.toString?c.toString():"Unknown error",d=f+" attempting to load TileSource"}i.raiseEvent("open-failed",{message:d,source:a})}})},supports:function(){return!1},configure:function(){throw new Error("Method not implemented.")},getTileUrl:function(){throw new Error("Method not implemented.")},tileExists:function(a,b,c){var d=this.getNumTiles(a);return a>=this.minLevel&&a<=this.maxLevel&&b>=0&&c>=0&&b=0;c--)for(d=this.displayRects[c],e=d.minLevel;e<=d.maxLevel;e++)this._levelRects[e]||(this._levelRects[e]=[]),this._levelRects[e].push(d);a.TileSource.apply(this,[f])},a.extend(a.DziTileSource.prototype,a.TileSource.prototype,{supports:function(a){var b;return a.Image?b=a.Image.xmlns:a.documentElement&&("Image"==a.documentElement.localName||"Image"==a.documentElement.tagName)&&(b=a.documentElement.namespaceURI),"http://schemas.microsoft.com/deepzoom/2008"==b||"http://schemas.microsoft.com/deepzoom/2009"==b},configure:function(d,e){var f;return f=a.isPlainObject(d)?c(this,d):b(this,d),e&&!f.tilesUrl&&(f.tilesUrl=e.replace(/([^\/]+)\.(dzi|xml|js)(\?.*|$)/,"$1_files/"),f.queryParams=-1!=e.search(/\.(dzi|xml|js)\?/)?e.match(/\?.*/):""),f},getTileUrl:function(a,b,c){return[this.tilesUrl,a,"/",b,"_",c,".",this.fileFormat,this.queryParams].join("")},tileExists:function(a,b,c){var d,e,f,g,h,i,j,k=this._levelRects[a];if(!k||!k.length)return!0;for(j=k.length-1;j>=0;j--)if(d=k[j],!(ad.maxLevel)&&(e=this.getLevelScale(a),f=d.x*e,g=d.y*e,h=f+d.width*e,i=g+d.height*e,f=Math.floor(f/this.tileSize),g=Math.floor(g/this.tileSize),h=Math.ceil(h/this.tileSize),i=Math.ceil(i/this.tileSize),b>=f&&h>b&&c>=g&&i>c))return!0;return!1}})}(OpenSeadragon),function(a){function b(b){if(!b||!b.documentElement)throw new Error(a.getString("Errors.Xml"));var d=b.documentElement,e=d.tagName,f=null;if("info"==e)try{return f={},c(d,f),f}catch(g){throw g instanceof Error?g:new Error(a.getString("Errors.IIIF"))}throw new Error(a.getString("Errors.IIIF"))}function c(b,d,e){var f,g;if(3==b.nodeType&&e)g=b.nodeValue.trim(),g.match(/^\d*$/)&&(g=Number(g)),d[e]?(a.isArray(d[e])||(d[e]=[d[e]]),d[e].push(g)):d[e]=g;else if(1==b.nodeType)for(f=0;f0?Math.max.apply(null,h):f,this.tile_width=b.tileSize,this.tile_height=b.tileSize}b.maxLevel||(b.maxLevel=this.scale_factors?Math.floor(Math.pow(Math.max.apply(null,this.scale_factors),.5)):Number(Math.ceil(Math.log(Math.max(this.width,this.height),2)))),a.TileSource.apply(this,[b])},a.extend(a.IIIFTileSource.prototype,a.TileSource.prototype,{supports:function(a){return a.protocol&&"http://iiif.io/api/image"==a.protocol?!0:!a["@context"]||"http://library.stanford.edu/iiif/image-api/1.1/context.json"!=a["@context"]&&"http://iiif.io/api/image/1/context.json"!=a["@context"]?a.profile&&0===a.profile.indexOf("http://library.stanford.edu/iiif/image-api/compliance.html")?!0:a.identifier&&a.width&&a.height?!0:a.documentElement&&"info"==a.documentElement.tagName&&"http://library.stanford.edu/iiif/image-api/ns/"==a.documentElement.namespaceURI?!0:!1:!0},configure:function(c,d){if(a.isPlainObject(c))return c["@context"]?c:(c["@context"]="http://iiif.io/api/image/1.0/context.json",c["@id"]=d.replace("/info.json",""),c);var e=b(c);return e["@context"]="http://iiif.io/api/image/1.0/context.json",e["@id"]=d.replace("/info.xml",""),e},getTileSize:function(a){var b=Math.pow(2,this.maxLevel-a);return this.tileSizePerScaleFactor&&this.tileSizePerScaleFactor[b]&&(this.tileSize=this.tileSizePerScaleFactor[b]),this.tileSize},getTileUrl:function(a,b,c){var d,e,f,g,h,i,j,k,l,m,n,o="0",p=Math.pow(.5,this.maxLevel-a),q=Math.ceil(this.width*p),r=Math.ceil(this.height*p);return d=this.getTileSize(a),e=Math.ceil(d/p),f=e,m=this["@context"].indexOf("/1.0/context.json")>-1||this["@context"].indexOf("/1.1/context.json")>-1||this["@context"].indexOf("/1/context.json")>-1?"native.jpg":"default.jpg",d>q&&d>r?(l=q+",",g="full"):(h=b*e,i=c*f,j=Math.min(e,this.width-h),k=Math.min(f,this.height-i),l=Math.ceil(j*p)+",",g=[h,i,j,k].join(",")),n=[this["@id"],g,l,o,m].join("/")}})}(OpenSeadragon),function(a){a.OsmTileSource=function(b){var c;c=a.isPlainObject(b)?b:{width:arguments[0],height:arguments[1],tileSize:arguments[2],tileOverlap:arguments[3],tilesUrl:arguments[4]},c.width&&c.height||(c.width=65572864,c.height=65572864),c.tileSize||(c.tileSize=256,c.tileOverlap=0),c.tilesUrl||(c.tilesUrl="http://tile.openstreetmap.org/"),c.minLevel=8,a.TileSource.apply(this,[c])},a.extend(a.OsmTileSource.prototype,a.TileSource.prototype,{supports:function(a){return a.type&&"openstreetmaps"==a.type},configure:function(a){return a},getTileUrl:function(a,b,c){return this.tilesUrl+(a-8)+"/"+b+"/"+c+".png"}})}(OpenSeadragon),function(a){a.TmsTileSource=function(b){var c;c=a.isPlainObject(b)?b:{width:arguments[0],height:arguments[1],tileSize:arguments[2],tileOverlap:arguments[3],tilesUrl:arguments[4]};var d,e=256*Math.ceil(c.width/256),f=256*Math.ceil(c.height/256);d=e>f?e/256:f/256,c.maxLevel=Math.ceil(Math.log(d)/Math.log(2))-1,c.tileSize=256,c.width=e,c.height=f,a.TileSource.apply(this,[c])},a.extend(a.TmsTileSource.prototype,a.TileSource.prototype,{supports:function(a){return a.type&&"tiledmapservice"==a.type},configure:function(a){return a},getTileUrl:function(a,b,c){var d=this.getNumTiles(a).y-1;return this.tilesUrl+a+"/"+b+"/"+(d-c)+".png"}})}(OpenSeadragon),function(a){function b(b){var c,d,e=[];for(d=0;d");return e.sort(function(a,b){return a.height-b.height})}function c(b,c){if(!c||!c.documentElement)throw new Error(a.getString("Errors.Xml"));var e,f,g=c.documentElement,h=g.tagName,i=null,j=[];if("image"==h)try{for(i={type:g.getAttribute("type"),levels:[]},j=g.getElementsByTagName("level"),f=0;f0?(e=d.levels[d.levels.length-1].width,f=d.levels[d.levels.length-1].height):(e=0,f=0,a.console.error("No supported image formats found")),a.extend(!0,d,{width:e,height:f,tileSize:Math.max(f,e),tileOverlap:0,minLevel:0,maxLevel:d.levels.length>0?d.levels.length-1:0}),a.TileSource.apply(this,[d]),this.levels=d.levels},a.extend(a.LegacyTileSource.prototype,a.TileSource.prototype,{supports:function(a){return a.type&&"legacy-image-pyramid"==a.type||a.documentElement&&"legacy-image-pyramid"==a.documentElement.getAttribute("type")},configure:function(b){var e;return e=a.isPlainObject(b)?d(this,b):c(this,b)},getLevelScale:function(a){var b=0/0;return this.levels.length>0&&a>=this.minLevel&&a<=this.maxLevel&&(b=this.levels[a].width/this.levels[this.maxLevel].width),b},getNumTiles:function(b){var c=this.getLevelScale(b);return c?new a.Point(1,1):new a.Point(0,0)},getTileAtPoint:function(){return new a.Point(0,0)},getTileUrl:function(a){var b=null;return this.levels.length>0&&a>=this.minLevel&&a<=this.maxLevel&&(b=this.levels[a].url),b}})}(OpenSeadragon),function(a){a.TileSourceCollection=function(){a.console.error("TileSourceCollection is deprecated; use World instead")}}(OpenSeadragon),function(a){function b(b){a.requestAnimationFrame(function(){c(b)})}function c(c){var d,e,f;c.shouldFade&&(d=a.now(),e=d-c.fadeBeginTime,f=1-e/c.fadeLength,f=Math.min(1,f),f=Math.max(0,f),c.imgGroup&&a.setElementOpacity(c.imgGroup,f,!0),f>0&&b(c))}function d(c){c.shouldFade=!0,c.fadeBeginTime=a.now()+c.fadeDelay,window.setTimeout(function(){b(c)},c.fadeDelay)}function e(b){b.shouldFade=!1,b.imgGroup&&a.setElementOpacity(b.imgGroup,1,!0)}function f(b,c){b.element.disabled||(c>=a.ButtonState.GROUP&&b.currentState==a.ButtonState.REST&&(e(b),b.currentState=a.ButtonState.GROUP),c>=a.ButtonState.HOVER&&b.currentState==a.ButtonState.GROUP&&(b.imgHover&&(b.imgHover.style.visibility=""),b.currentState=a.ButtonState.HOVER),c>=a.ButtonState.DOWN&&b.currentState==a.ButtonState.HOVER&&(b.imgDown&&(b.imgDown.style.visibility=""),b.currentState=a.ButtonState.DOWN))}function g(b,c){b.element.disabled||(c<=a.ButtonState.HOVER&&b.currentState==a.ButtonState.DOWN&&(b.imgDown&&(b.imgDown.style.visibility="hidden"),b.currentState=a.ButtonState.HOVER),c<=a.ButtonState.GROUP&&b.currentState==a.ButtonState.HOVER&&(b.imgHover&&(b.imgHover.style.visibility="hidden"),b.currentState=a.ButtonState.GROUP),c<=a.ButtonState.REST&&b.currentState==a.ButtonState.GROUP&&(d(b),b.currentState=a.ButtonState.REST))}a.ButtonState={REST:0,GROUP:1,HOVER:2,DOWN:3},a.Button=function(b){var c=this;a.EventSource.call(this),a.extend(!0,this,{tooltip:null,srcRest:null,srcGroup:null,srcHover:null,srcDown:null,clickTimeThreshold:a.DEFAULT_SETTINGS.clickTimeThreshold,clickDistThreshold:a.DEFAULT_SETTINGS.clickDistThreshold,fadeDelay:0,fadeLength:2e3,onPress:null,onRelease:null,onClick:null,onEnter:null,onExit:null,onFocus:null,onBlur:null},b),this.element=b.element||a.makeNeutralElement("div"),b.element||(this.imgRest=a.makeTransparentImage(this.srcRest),this.imgGroup=a.makeTransparentImage(this.srcGroup),this.imgHover=a.makeTransparentImage(this.srcHover),this.imgDown=a.makeTransparentImage(this.srcDown),this.imgRest.alt=this.imgGroup.alt=this.imgHover.alt=this.imgDown.alt=this.tooltip,this.element.style.position="relative",a.setElementTouchActionNone(this.element),this.imgGroup.style.position=this.imgHover.style.position=this.imgDown.style.position="absolute",this.imgGroup.style.top=this.imgHover.style.top=this.imgDown.style.top="0px",this.imgGroup.style.left=this.imgHover.style.left=this.imgDown.style.left="0px",this.imgHover.style.visibility=this.imgDown.style.visibility="hidden",a.Browser.vendor==a.BROWSERS.FIREFOX&&a.Browser.version<3&&(this.imgGroup.style.top=this.imgHover.style.top=this.imgDown.style.top=""),this.element.appendChild(this.imgRest),this.element.appendChild(this.imgGroup),this.element.appendChild(this.imgHover),this.element.appendChild(this.imgDown)),this.addHandler("press",this.onPress),this.addHandler("release",this.onRelease),this.addHandler("click",this.onClick),this.addHandler("enter",this.onEnter),this.addHandler("exit",this.onExit),this.addHandler("focus",this.onFocus),this.addHandler("blur",this.onBlur),this.currentState=a.ButtonState.GROUP,this.fadeBeginTime=null,this.shouldFade=!1,this.element.style.display="inline-block",this.element.style.position="relative",this.element.title=this.tooltip,this.tracker=new a.MouseTracker({element:this.element,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,enterHandler:function(b){b.insideElementPressed?(f(c,a.ButtonState.DOWN),c.raiseEvent("enter",{originalEvent:b.originalEvent})):b.buttonDownAny||f(c,a.ButtonState.HOVER)},focusHandler:function(a){this.enterHandler(a),c.raiseEvent("focus",{originalEvent:a.originalEvent})},exitHandler:function(b){g(c,a.ButtonState.GROUP),b.insideElementPressed&&c.raiseEvent("exit",{originalEvent:b.originalEvent})},blurHandler:function(a){this.exitHandler(a),c.raiseEvent("blur",{originalEvent:a.originalEvent})},pressHandler:function(b){f(c,a.ButtonState.DOWN),c.raiseEvent("press",{originalEvent:b.originalEvent})},releaseHandler:function(b){b.insideElementPressed&&b.insideElementReleased?(g(c,a.ButtonState.HOVER),c.raiseEvent("release",{originalEvent:b.originalEvent})):b.insideElementPressed?g(c,a.ButtonState.GROUP):f(c,a.ButtonState.HOVER)},clickHandler:function(a){a.quick&&c.raiseEvent("click",{originalEvent:a.originalEvent})},keyHandler:function(a){return 13===a.keyCode?(c.raiseEvent("click",{originalEvent:a.originalEvent}),c.raiseEvent("release",{originalEvent:a.originalEvent}),!1):!0}}),g(this,a.ButtonState.REST)},a.extend(a.Button.prototype,a.EventSource.prototype,{notifyGroupEnter:function(){f(this,a.ButtonState.GROUP)},notifyGroupExit:function(){g(this,a.ButtonState.REST)},disable:function(){this.notifyGroupExit(),this.element.disabled=!0,a.setElementOpacity(this.element,.2,!0)},enable:function(){this.element.disabled=!1,a.setElementOpacity(this.element,1,!0),this.notifyGroupEnter()}})}(OpenSeadragon),function(a){a.ButtonGroup=function(b){a.extend(!0,this,{buttons:[],clickTimeThreshold:a.DEFAULT_SETTINGS.clickTimeThreshold,clickDistThreshold:a.DEFAULT_SETTINGS.clickDistThreshold,labelText:""},b);var c,d=this.buttons.concat([]),e=this;if(this.element=b.element||a.makeNeutralElement("div"),!b.group)for(this.label=a.makeNeutralElement("label"),this.element.style.display="inline-block",this.element.appendChild(this.label),c=0;c0?c>-(f-h.x)&&(this.element.style.marginLeft=c+2*b.delta.x+"px",d(this,h.x,c+2*b.delta.x)):-b.delta.x<0&&0>c&&(this.element.style.marginLeft=c+2*b.delta.x+"px",d(this,h.x,c+2*b.delta.x)):-b.delta.y>0?e>-(g-h.y)&&(this.element.style.marginTop=e+2*b.delta.y+"px",d(this,h.y,e+2*b.delta.y)):-b.delta.y<0&&0>e&&(this.element.style.marginTop=e+2*b.delta.y+"px",d(this,h.y,e+2*b.delta.y))),!1}function c(b){var c=Number(this.element.style.marginLeft.replace("px","")),e=Number(this.element.style.marginTop.replace("px","")),f=Number(this.element.style.width.replace("px","")),g=Number(this.element.style.height.replace("px","")),h=a.getElementSize(this.viewer.canvas);return this.element&&("horizontal"==this.scroll?b.scroll>0?c>-(f-h.x)&&(this.element.style.marginLeft=c-60*b.scroll+"px",d(this,h.x,c-60*b.scroll)):b.scroll<0&&0>c&&(this.element.style.marginLeft=c-60*b.scroll+"px",d(this,h.x,c-60*b.scroll)):b.scroll<0?e>h.y-g&&(this.element.style.marginTop=e+60*b.scroll+"px",d(this,h.y,e+60*b.scroll)):b.scroll>0&&0>e&&(this.element.style.marginTop=e+60*b.scroll+"px",d(this,h.y,e+60*b.scroll))),!1}function d(b,c,d){var e,f,g,h,i,j,k;for(e="horizontal"==b.scroll?b.panelWidth:b.panelHeight,f=Math.ceil(c/e)+5,g=Math.ceil((Math.abs(d)+c)/e)+1,f=g-f,f=0>f?0:f,j=f;g>j&&jj+g.x-this.panelWidth?(c=Math.min(c,h-g.x),this.element.style.marginLeft=-c+"px",d(this,g.x,-c)):j>c&&(c=Math.max(0,c-g.x/2),this.element.style.marginLeft=-c+"px",d(this,g.x,-c))):(c=Number(b)*(this.panelHeight+3),c>k+g.y-this.panelHeight?(c=Math.min(c,i-g.y),this.element.style.marginTop=-c+"px",d(this,g.y,-c)):k>c&&(c=Math.max(0,c-g.y/2),this.element.style.marginTop=-c+"px",d(this,g.y,-c))),this.currentPage=b,a.getElement(f.id+"-displayregion").focus(),e.call(this,{eventSource:this.innerTracker}))},update:function(){return i[this.id].animating?(a.console.log("image reference strip update"),!0):!1},destroy:function(){this.element&&this.element.parentNode.removeChild(this.element)}})}(OpenSeadragon),function(a){a.DisplayRect=function(b,c,d,e,f,g){a.Rect.apply(this,[b,c,d,e]),this.minLevel=f,this.maxLevel=g},a.extend(a.DisplayRect.prototype,a.Rect.prototype)}(OpenSeadragon),function(a){function b(a,b){return(1-Math.exp(a*-b))/(1-Math.exp(-a))}a.Spring=function(b){var c=arguments;"object"!=typeof b&&(b={initial:c.length&&"number"==typeof c[0]?c[0]:void 0,springStiffness:c.length>1?c[1].springStiffness:5,animationTime:c.length>1?c[1].animationTime:1.5}),a.console.assert("number"==typeof b.springStiffness&&0!==b.springStiffness,"[OpenSeadragon.Spring] options.springStiffness must be a non-zero number"),a.console.assert("number"==typeof b.animationTime&&0!==b.springStiffness,"[OpenSeadragon.Spring] options.animationTime must be a non-zero number"),b.exponential&&(this._exponential=!0,delete b.exponential),a.extend(!0,this,b),this.current={value:"number"==typeof this.initial?this.initial:this._exponential?0:1,time:a.now()},a.console.assert(!this._exponential||0!==this.current.value,"[OpenSeadragon.Spring] value must be non-zero for exponential springs"),this.start={value:this.current.value,time:this.current.time},this.target={value:this.current.value,time:this.current.time},this._exponential&&(this.start._logValue=Math.log(this.start.value),this.target._logValue=Math.log(this.target.value),this.current._logValue=Math.log(this.current.value))},a.Spring.prototype={resetTo:function(b){a.console.assert(!this._exponential||0!==b,"[OpenSeadragon.Spring.resetTo] target must be non-zero for exponential springs"),this.start.value=this.target.value=this.current.value=b,this.start.time=this.target.time=this.current.time=a.now(),this._exponential&&(this.start._logValue=Math.log(this.start.value),this.target._logValue=Math.log(this.target.value),this.current._logValue=Math.log(this.current.value))},springTo:function(b){a.console.assert(!this._exponential||0!==b,"[OpenSeadragon.Spring.springTo] target must be non-zero for exponential springs"),this.start.value=this.current.value,this.start.time=this.current.time,this.target.value=b,this.target.time=this.start.time+1e3*this.animationTime,this._exponential&&(this.start._logValue=Math.log(this.start.value),this.target._logValue=Math.log(this.target.value))},shiftBy:function(b){this.start.value+=b,this.target.value+=b,this._exponential&&(a.console.assert(0!==this.target.value&&0!==this.start.value,"[OpenSeadragon.Spring.shiftBy] spring value must be non-zero for exponential springs"),this.start._logValue=Math.log(this.start.value),this.target._logValue=Math.log(this.target.value))},setExponential:function(b){this._exponential=b,this._exponential&&(a.console.assert(0!==this.current.value&&0!==this.target.value&&0!==this.start.value,"[OpenSeadragon.Spring.setExponential] spring value must be non-zero for exponential springs"),this.start._logValue=Math.log(this.start.value),this.target._logValue=Math.log(this.target.value),this.current._logValue=Math.log(this.current.value))},update:function(){this.current.time=a.now();var c,d;this._exponential?(c=this.start._logValue,d=this.target._logValue):(c=this.start.value,d=this.target.value);var e=this.current.time>=this.target.time?d:c+(d-c)*b(this.springStiffness,(this.current.time-this.start.time)/(this.target.time-this.start.time));this.current.value=this._exponential?Math.exp(e):e}}}(OpenSeadragon),function(a){function b(b){a.extend(!0,this,{timeout:a.DEFAULT_SETTINGS.timeout,jobId:null},b),this.image=null}function c(a,b,c){var d;a.jobsInProgress--,(!a.jobLimit||a.jobsInProgress0&&(d=a.jobQueue.shift(),d.start(),a.jobsInProgress++),c(b.image)}b.prototype={start:function(){var a=this;this.image=new Image,this.crossOriginPolicy!==!1&&(this.image.crossOrigin=this.crossOriginPolicy),this.image.onload=function(){a.finish(!0)},this.image.onabort=this.image.onerror=function(){a.finish(!1)},this.jobId=window.setTimeout(function(){a.finish(!1)},this.timeout),this.image.src=this.src},finish:function(a){this.image.onload=this.image.onerror=this.image.onabort=null,a||(this.image=null),this.jobId&&window.clearTimeout(this.jobId),this.callback(this)}},a.ImageLoader=function(b){a.extend(!0,this,{jobLimit:a.DEFAULT_SETTINGS.imageLoaderLimit,jobQueue:[],jobsInProgress:0},b)},a.ImageLoader.prototype={addJob:function(a){var d=this,e=function(b){c(d,b,a.callback)},f={src:a.src,crossOriginPolicy:a.crossOriginPolicy,callback:e,abort:a.abort},g=new b(f);!this.jobLimit||this.jobsInProgressc&&(c=e)}return c},needsUpdate:function(){return a.console.error("[Drawer.needsUpdate] this function is deprecated. Use World.needsDraw instead."),this.viewer.world.needsDraw()},numTilesLoaded:function(){return a.console.error("[Drawer.numTilesLoaded] this function is deprecated. Use TileCache.numTilesLoaded instead."),this.viewer.tileCache.numTilesLoaded()},reset:function(){return a.console.error("[Drawer.reset] this function is deprecated. Use World.resetItems instead."),this.viewer.world.resetItems(),this},update:function(){return a.console.error("[Drawer.update] this function is deprecated. Use Drawer.clear and World.draw instead."),this.clear(),this.viewer.world.draw(),this},canRotate:function(){return this.useCanvas},destroy:function(){this.canvas.width=1,this.canvas.height=1,this.sketchCanvas=null,this.sketchContext=null},clear:function(){if(this.canvas.innerHTML="",this.useCanvas){var a=this._calculateCanvasSize();(this.canvas.width!=a.x||this.canvas.height!=a.y)&&(this.canvas.width=a.x,this.canvas.height=a.y,null!==this.sketchCanvas&&(this.sketchCanvas.width=this.canvas.width,this.sketchCanvas.height=this.canvas.height)),this._clear()}},_clear:function(a){if(this.useCanvas){var b=this._getContext(a),c=b.canvas;b.clearRect(0,0,c.width,c.height)}},viewportToDrawerRectangle:function(b){var c=this.viewport.pixelFromPoint(b.getTopLeft(),!0),d=this.viewport.deltaPixelsFromPoints(b.getSize(),!0);return new a.Rect(c.x*a.pixelDensityRatio,c.y*a.pixelDensityRatio,d.x*a.pixelDensityRatio,d.y*a.pixelDensityRatio)},drawTile:function(b,c,d){if(a.console.assert(b,"[Drawer.drawTile] tile is required"),a.console.assert(c,"[Drawer.drawTile] drawingHandler is required"),this.useCanvas){var e=this._getContext(d);0!==this.viewport.degrees?(this._offsetForRotation(b,this.viewport.degrees,d),b.drawCanvas(e,c),this._restoreRotationChanges(b,d)):b.drawCanvas(e,c)}else b.drawHTML(this.canvas)},_getContext:function(a){var b=this.context;return a&&(null===this.sketchCanvas&&(this.sketchCanvas=document.createElement("canvas"),this.sketchCanvas.width=this.canvas.width,this.sketchCanvas.height=this.canvas.height,this.sketchContext=this.sketchCanvas.getContext("2d")),b=this.sketchContext),b},saveContext:function(a){this.useCanvas&&this._getContext(a).save()},restoreContext:function(a){this.useCanvas&&this._getContext(a).restore()},setClip:function(a,b){if(this.useCanvas){var c=this._getContext(b);c.beginPath(),c.rect(a.x,a.y,a.width,a.height),c.clip()}},drawRectangle:function(a,b,c){if(this.useCanvas){var d=this._getContext(c);d.save(),d.fillStyle=b,d.fillRect(a.x,a.y,a.width,a.height),d.restore()}},blendSketch:function(a){this.useCanvas&&this.sketchCanvas&&(this.context.save(),this.context.globalAlpha=a,this.context.drawImage(this.sketchCanvas,0,0),this.context.restore())},drawDebugInfo:function(b,c,d){if(this.useCanvas){var e=this.context;e.save(),e.lineWidth=2*a.pixelDensityRatio,e.font="small-caps bold "+13*a.pixelDensityRatio+"px arial",e.strokeStyle=this.debugGridColor,e.fillStyle=this.debugGridColor,0!==this.viewport.degrees&&this._offsetForRotation(b,this.viewport.degrees),e.strokeRect(b.position.x*a.pixelDensityRatio,b.position.y*a.pixelDensityRatio,b.size.x*a.pixelDensityRatio,b.size.y*a.pixelDensityRatio);var f=(b.position.x+b.size.x/2)*a.pixelDensityRatio,g=(b.position.y+b.size.y/2)*a.pixelDensityRatio;e.translate(f,g),e.rotate(Math.PI/180*-this.viewport.degrees),e.translate(-f,-g),0===b.x&&0===b.y&&(e.fillText("Zoom: "+this.viewport.getZoom(),b.position.x*a.pixelDensityRatio,(b.position.y-30)*a.pixelDensityRatio),e.fillText("Pan: "+this.viewport.getBounds().toString(),b.position.x*a.pixelDensityRatio,(b.position.y-20)*a.pixelDensityRatio)),e.fillText("Level: "+b.level,(b.position.x+10)*a.pixelDensityRatio,(b.position.y+20)*a.pixelDensityRatio),e.fillText("Column: "+b.x,(b.position.x+10)*a.pixelDensityRatio,(b.position.y+30)*a.pixelDensityRatio),e.fillText("Row: "+b.y,(b.position.x+10)*a.pixelDensityRatio,(b.position.y+40)*a.pixelDensityRatio),e.fillText("Order: "+d+" of "+c,(b.position.x+10)*a.pixelDensityRatio,(b.position.y+50)*a.pixelDensityRatio),e.fillText("Size: "+b.size.toString(),(b.position.x+10)*a.pixelDensityRatio,(b.position.y+60)*a.pixelDensityRatio),e.fillText("Position: "+b.position.toString(),(b.position.x+10)*a.pixelDensityRatio,(b.position.y+70)*a.pixelDensityRatio),0!==this.viewport.degrees&&this._restoreRotationChanges(b),e.restore()}},debugRect:function(b){if(this.useCanvas){var c=this.context;c.save(),c.lineWidth=2*a.pixelDensityRatio,c.strokeStyle=this.debugGridColor,c.fillStyle=this.debugGridColor,c.strokeRect(b.x*a.pixelDensityRatio,b.y*a.pixelDensityRatio,b.width*a.pixelDensityRatio,b.height*a.pixelDensityRatio),c.restore()}},_offsetForRotation:function(a,b,c){var d=this.canvas.width/2,e=this.canvas.height/2,f=a.position.x-d,g=a.position.y-e,h=this._getContext(c);h.save(),h.translate(d,e),h.rotate(Math.PI/180*b),a.position.x=f,a.position.y=g},_restoreRotationChanges:function(a,b){var c=this.canvas.width/2,d=this.canvas.height/2,e=a.position.x+c,f=a.position.y+d;a.position.x=e,a.position.y=f;var g=this._getContext(b);g.restore()},_calculateCanvasSize:function(){var b=a.pixelDensityRatio,c=this.viewport.getContainerSize();return{x:c.x*b,y:c.y*b}}}}(OpenSeadragon),function(a){a.Viewport=function(b){var c=arguments;c.length&&c[0]instanceof a.Point&&(b={containerSize:c[0],contentSize:c[1],config:c[2]}),b.config&&(a.extend(!0,b,b.config),delete b.config),this._margins=a.extend({left:0,top:0,right:0,bottom:0},b.margins||{}),delete b.margins,a.extend(!0,this,{containerSize:null,contentSize:null,zoomPoint:null,viewer:null,springStiffness:a.DEFAULT_SETTINGS.springStiffness,animationTime:a.DEFAULT_SETTINGS.animationTime,minZoomImageRatio:a.DEFAULT_SETTINGS.minZoomImageRatio,maxZoomPixelRatio:a.DEFAULT_SETTINGS.maxZoomPixelRatio,visibilityRatio:a.DEFAULT_SETTINGS.visibilityRatio,wrapHorizontal:a.DEFAULT_SETTINGS.wrapHorizontal,wrapVertical:a.DEFAULT_SETTINGS.wrapVertical,defaultZoomLevel:a.DEFAULT_SETTINGS.defaultZoomLevel,minZoomLevel:a.DEFAULT_SETTINGS.minZoomLevel,maxZoomLevel:a.DEFAULT_SETTINGS.maxZoomLevel,degrees:a.DEFAULT_SETTINGS.degrees,homeFillsViewer:a.DEFAULT_SETTINGS.homeFillsViewer},b),this._containerInnerSize=new a.Point(Math.max(1,this.containerSize.x-(this._margins.left+this._margins.right)),Math.max(1,this.containerSize.y-(this._margins.top+this._margins.bottom))),this.centerSpringX=new a.Spring({initial:0,springStiffness:this.springStiffness,animationTime:this.animationTime}),this.centerSpringY=new a.Spring({initial:0,springStiffness:this.springStiffness,animationTime:this.animationTime}),this.zoomSpring=new a.Spring({exponential:!0,initial:1,springStiffness:this.springStiffness,animationTime:this.animationTime}),this._oldCenterX=this.centerSpringX.current.value,this._oldCenterY=this.centerSpringY.current.value,this._oldZoom=this.zoomSpring.current.value,this.contentSize?this.resetContentSize(this.contentSize):this.setHomeBounds(new a.Rect(0,0,1,1),1),this.goHome(!0),this.update()},a.Viewport.prototype={resetContentSize:function(b){return a.console.assert(b,"[Viewport.resetContentSize] contentSize is required"),a.console.assert(b instanceof a.Point,"[Viewport.resetContentSize] contentSize must be an OpenSeadragon.Point"),a.console.assert(b.x>0,"[Viewport.resetContentSize] contentSize.x must be greater than 0"),a.console.assert(b.y>0,"[Viewport.resetContentSize] contentSize.y must be greater than 0"),this.setHomeBounds(new a.Rect(0,0,1,b.y/b.x),b.x),this},setHomeBounds:function(b,c){a.console.assert(b,"[Viewport.setHomeBounds] bounds is required"),a.console.assert(b instanceof a.Rect,"[Viewport.setHomeBounds] bounds must be an OpenSeadragon.Rect"),a.console.assert(b.width>0,"[Viewport.setHomeBounds] bounds.width must be greater than 0"),a.console.assert(b.height>0,"[Viewport.setHomeBounds] bounds.height must be greater than 0"),this.homeBounds=b.clone(),this.contentSize=this.homeBounds.getSize().times(c),this.contentAspectX=this.contentSize.x/this.contentSize.y,this.contentAspectY=this.contentSize.y/this.contentSize.x,this.viewer&&this.viewer.raiseEvent("reset-size",{contentSize:this.contentSize.clone(),contentFactor:c,homeBounds:this.homeBounds.clone()})},getHomeZoom:function(){if(this.defaultZoomLevel)return this.defaultZoomLevel;var a,b=this.contentAspectX/this.getAspectRatio();return a=this.homeFillsViewer?b>=1?b:1:b>=1?1:b,a/this.homeBounds.width},getHomeBounds:function(){var b=this.homeBounds.getCenter(),c=1/this.getHomeZoom(),d=c/this.getAspectRatio();return new a.Rect(b.x-c/2,b.y-d/2,c,d)},goHome:function(a){return this.viewer&&this.viewer.raiseEvent("home",{immediately:a}),this.fitBounds(this.getHomeBounds(),a)},getMinZoom:function(){var a=this.getHomeZoom(),b=this.minZoomLevel?this.minZoomLevel:this.minZoomImageRatio*a;return b},getMaxZoom:function(){var a=this.maxZoomLevel;return a||(a=this.contentSize.x*this.maxZoomPixelRatio/this._containerInnerSize.x,a/=this.homeBounds.width),Math.max(a,this.getHomeZoom())},getAspectRatio:function(){return this._containerInnerSize.x/this._containerInnerSize.y},getContainerSize:function(){return new a.Point(this.containerSize.x,this.containerSize.y)},getBounds:function(b){var c=this.getCenter(b),d=1/this.getZoom(b),e=d/this.getAspectRatio();return new a.Rect(c.x-d/2,c.y-e/2,d,e)},getBoundsWithMargins:function(a){var b=this.getBounds(a),c=this._containerInnerSize.x*this.getZoom(a);return b.x-=this._margins.left/c,b.y-=this._margins.top/c,b.width+=(this._margins.left+this._margins.right)/c,b.height+=(this._margins.top+this._margins.bottom)/c,b},getCenter:function(b){var c,d,e,f,g,h,i,j,k=new a.Point(this.centerSpringX.current.value,this.centerSpringY.current.value),l=new a.Point(this.centerSpringX.target.value,this.centerSpringY.target.value);return b?k:this.zoomPoint?(c=this.pixelFromPoint(this.zoomPoint,!0),d=this.getZoom(),e=1/d,f=e/this.getAspectRatio(),g=new a.Rect(k.x-e/2,k.y-f/2,e,f),h=this._pixelFromPoint(this.zoomPoint,g),i=h.minus(c),j=i.divide(this._containerInnerSize.x*d),l.plus(j)):l},getZoom:function(a){return a?this.zoomSpring.current.value:this.zoomSpring.target.value},_applyBoundaryConstraints:function(b,c){var d=0,e=0,f=new a.Rect(b.x,b.y,b.width,b.height),g=this.visibilityRatio*f.width,h=this.visibilityRatio*f.height;if(this.wrapHorizontal);else{var i=f.x+(f.width-g);this.homeBounds.x>i&&(d=this.homeBounds.x-i);var j=this.homeBounds.x+this.homeBounds.width,k=f.x+g;if(k>j){var l=j-k;d=d?(d+l)/2:l}}if(this.wrapVertical);else{var m=f.y+(f.height-h);this.homeBounds.y>m&&(e=this.homeBounds.y-m);var n=this.homeBounds.y+this.homeBounds.height,o=f.y+h;if(o>n){var p=n-o;e=e?(e+p)/2:p}}return(d||e)&&(f.x+=d,f.y+=e),this.viewer&&this.viewer.raiseEvent("constrain",{immediately:c}),f},applyConstraints:function(a){var b,c,d=this.getZoom(),e=Math.max(Math.min(d,this.getMaxZoom()),this.getMinZoom());return d!=e&&this.zoomTo(e,this.zoomPoint,a),b=this.getBounds(),c=this._applyBoundaryConstraints(b,a),(b.x!==c.x||b.y!==c.y||a)&&this.fitBounds(c,a),this},ensureVisible:function(a){return this.applyConstraints(a)},_fitBounds:function(b,c){c=c||{};var d,e,f,g,h,i,j=c.immediately||!1,k=c.constraints||!1,l=this.getAspectRatio(),m=b.getCenter(),n=new a.Rect(b.x,b.y,b.width,b.height);return n.getAspectRatio()>=l?(n.height=b.width/l,n.y=m.y-n.height/2):(n.width=b.height*l,n.x=m.x-n.width/2),k&&(h=n.getAspectRatio()),this.panTo(this.getCenter(!0),!0),this.zoomTo(this.getZoom(!0),null,!0),d=this.getBounds(),e=this.getZoom(),f=1/n.width,k&&(i=Math.max(Math.min(f,this.getMaxZoom()),this.getMinZoom()),f!==i&&(f=i,n.width=1/f,n.x=m.x-n.width/2,n.height=n.width/h,n.y=m.y-n.height/2),n=this._applyBoundaryConstraints(n,j),m=n.getCenter()),j?(this.panTo(m,!0),this.zoomTo(f,null,!0)):Math.abs(f-e)<1e-8||Math.abs(n.width-d.width)<1e-8?this.panTo(m,j):(g=d.getTopLeft().times(this._containerInnerSize.x/d.width).minus(n.getTopLeft().times(this._containerInnerSize.x/n.width)).divide(this._containerInnerSize.x/d.width-this._containerInnerSize.x/n.width),this.zoomTo(f,g,j))},fitBounds:function(a,b){return this._fitBounds(a,{immediately:b,constraints:!1})},fitBoundsWithConstraints:function(a,b){return this._fitBounds(a,{immediately:b,constraints:!0})},fitVertically:function(b){var c=new a.Rect(this.homeBounds.x+this.homeBounds.width/2,this.homeBounds.y,0,this.homeBounds.height);return this.fitBounds(c,b)},fitHorizontally:function(b){var c=new a.Rect(this.homeBounds.x,this.homeBounds.y+this.homeBounds.height/2,this.homeBounds.width,0);return this.fitBounds(c,b)},panBy:function(b,c){var d=new a.Point(this.centerSpringX.target.value,this.centerSpringY.target.value);return b=b.rotate(-this.degrees,new a.Point(0,0)),this.panTo(d.plus(b),c)},panTo:function(a,b){return b?(this.centerSpringX.resetTo(a.x),this.centerSpringY.resetTo(a.y)):(this.centerSpringX.springTo(a.x),this.centerSpringY.springTo(a.y)),this.viewer&&this.viewer.raiseEvent("pan",{center:a,immediately:b}),this},zoomBy:function(b,c,d){return c instanceof a.Point&&!isNaN(c.x)&&!isNaN(c.y)&&(c=c.rotate(-this.degrees,new a.Point(this.centerSpringX.target.value,this.centerSpringY.target.value))),this.zoomTo(this.zoomSpring.target.value*b,c,d)},zoomTo:function(b,c,d){return this.zoomPoint=c instanceof a.Point&&!isNaN(c.x)&&!isNaN(c.y)?c:null,d?this.zoomSpring.resetTo(b):this.zoomSpring.springTo(b),this.viewer&&this.viewer.raiseEvent("zoom",{zoom:b,refPoint:c,immediately:d}),this},setRotation:function(a){return this.viewer&&this.viewer.drawer.canRotate()?(a=(a+360)%360,this.degrees=a,this.viewer.forceRedraw(),null!==this.viewer&&this.viewer.raiseEvent("rotate",{degrees:a}),this):this},getRotation:function(){return this.degrees},resize:function(b,c){var d,e=this.getBounds(),f=e;return this.containerSize.x=b.x,this.containerSize.y=b.y,this._containerInnerSize=new a.Point(Math.max(1,b.x-(this._margins.left+this._margins.right)),Math.max(1,b.y-(this._margins.top+this._margins.bottom))),c&&(d=b.x/this.containerSize.x,f.width=e.width*d,f.height=f.width/this.getAspectRatio()),this.viewer&&this.viewer.raiseEvent("resize",{newContainerSize:b,maintain:c}),this.fitBounds(f,!0)},update:function(){var a,b,c,d;this.zoomPoint&&(a=this.pixelFromPoint(this.zoomPoint,!0)),this.zoomSpring.update(),this.zoomPoint&&this.zoomSpring.current.value!=this._oldZoom?(b=this.pixelFromPoint(this.zoomPoint,!0),c=b.minus(a),d=this.deltaPointsFromPixels(c,!0),this.centerSpringX.shiftBy(d.x),this.centerSpringY.shiftBy(d.y)):this.zoomPoint=null,this.centerSpringX.update(),this.centerSpringY.update();var e=this.centerSpringX.current.value!=this._oldCenterX||this.centerSpringY.current.value!=this._oldCenterY||this.zoomSpring.current.value!=this._oldZoom;return this._oldCenterX=this.centerSpringX.current.value,this._oldCenterY=this.centerSpringY.current.value,this._oldZoom=this.zoomSpring.current.value,e},deltaPixelsFromPoints:function(a,b){return a.times(this._containerInnerSize.x*this.getZoom(b))},deltaPointsFromPixels:function(a,b){return a.divide(this._containerInnerSize.x*this.getZoom(b))},pixelFromPoint:function(a,b){return this._pixelFromPoint(a,this.getBounds(b))},_pixelFromPoint:function(b,c){return b.minus(c.getTopLeft()).times(this._containerInnerSize.x/c.width).plus(new a.Point(this._margins.left,this._margins.top))},pointFromPixel:function(b,c){var d=this.getBounds(c);return b.minus(new a.Point(this._margins.left,this._margins.top)).divide(this._containerInnerSize.x/d.width).plus(d.getTopLeft())},_viewportToImageDelta:function(b,c){var d=this.homeBounds.width;return new a.Point(b*(this.contentSize.x/d),c*(this.contentSize.y*this.contentAspectX/d))},viewportToImageCoordinates:function(b,c){return 1==arguments.length?this.viewportToImageCoordinates(b.x,b.y):(this.viewer&&this.viewer.world.getItemCount()>1&&a.console.error("[Viewport.viewportToImageCoordinates] is not accurate with multi-image; use TiledImage.viewportToImageCoordinates instead."),this._viewportToImageDelta(b-this.homeBounds.x,c-this.homeBounds.y))},_imageToViewportDelta:function(b,c){var d=this.homeBounds.width;return new a.Point(b/this.contentSize.x*d,c/this.contentSize.y/this.contentAspectX*d)},imageToViewportCoordinates:function(b,c){if(1==arguments.length)return this.imageToViewportCoordinates(b.x,b.y);this.viewer&&this.viewer.world.getItemCount()>1&&a.console.error("[Viewport.imageToViewportCoordinates] is not accurate with multi-image; use TiledImage.imageToViewportCoordinates instead.");var d=this._imageToViewportDelta(b,c);return d.x+=this.homeBounds.x,d.y+=this.homeBounds.y,d},imageToViewportRectangle:function(b,c,d,e){var f,g,h;return 1==arguments.length?(h=b,this.imageToViewportRectangle(h.x,h.y,h.width,h.height)):(f=this.imageToViewportCoordinates(b,c),g=this._imageToViewportDelta(d,e),new a.Rect(f.x,f.y,g.x,g.y))},viewportToImageRectangle:function(b,c,d,e){var f,g,h;return 1==arguments.length?(h=b,this.viewportToImageRectangle(h.x,h.y,h.width,h.height)):(f=this.viewportToImageCoordinates(b,c),g=this._viewportToImageDelta(d,e),new a.Rect(f.x,f.y,g.x,g.y))},viewerElementToImageCoordinates:function(a){var b=this.pointFromPixel(a,!0);return this.viewportToImageCoordinates(b)},imageToViewerElementCoordinates:function(a){var b=this.imageToViewportCoordinates(a);return this.pixelFromPoint(b,!0)},windowToImageCoordinates:function(a){var b=a.minus(OpenSeadragon.getElementPosition(this.viewer.element));return this.viewerElementToImageCoordinates(b)},imageToWindowCoordinates:function(a){var b=this.imageToViewerElementCoordinates(a);return b.plus(OpenSeadragon.getElementPosition(this.viewer.element))},viewerElementToViewportCoordinates:function(a){return this.pointFromPixel(a,!0)},viewportToViewerElementCoordinates:function(a){return this.pixelFromPoint(a,!0)},windowToViewportCoordinates:function(a){var b=a.minus(OpenSeadragon.getElementPosition(this.viewer.element));return this.viewerElementToViewportCoordinates(b)},viewportToWindowCoordinates:function(a){var b=this.viewportToViewerElementCoordinates(a);return b.plus(OpenSeadragon.getElementPosition(this.viewer.element))},viewportToImageZoom:function(b){this.viewer&&this.viewer.world.getItemCount()>1&&a.console.error("[Viewport.viewportToImageZoom] is not accurate with multi-image.");var c=this.contentSize.x,d=this._containerInnerSize.x,e=this.homeBounds.width,f=d/c*e; +return b*f},imageToViewportZoom:function(b){this.viewer&&this.viewer.world.getItemCount()>1&&a.console.error("[Viewport.imageToViewportZoom] is not accurate with multi-image.");var c=this.contentSize.x,d=this._containerInnerSize.x,e=this.homeBounds.width,f=c/d/e;return b*f}}}(OpenSeadragon),function(a){function b(b){b._needsDraw=!1;var d,e,g,h,i,k,l,m,n=null,p=!1,q=a.now(),r=b.viewport.getBoundsWithMargins(!0),s=b.viewport.deltaPixelsFromPoints(b.source.getPixelRatio(0),!0).x*b._scaleSpring.current.value,t=Math.max(b.source.minLevel,Math.floor(Math.log(b.minZoomImageRatio)/Math.log(2))),u=Math.min(Math.abs(b.source.maxLevel),Math.abs(Math.floor(Math.log(s/b.minPixelRatio)/Math.log(2)))),v=b.viewport.degrees;for(r.x-=b._xSpring.current.value,r.y-=b._ySpring.current.value;b.lastDrawn.length>0;)d=b.lastDrawn.pop(),d.beingDrawn=!1;if(90===v||270===v)r=r.rotate(v);else if(0!==v&&180!==v){var w=r.rotate(90);r.x-=w.width/2,r.y-=w.height/2,r.width+=w.width,r.height+=w.height}var x=r.getTopLeft(),y=r.getBottomRight();if(!(!b.wrapHorizontal&&(y.x<0||x.x>b._worldWidthCurrent)||!b.wrapVertical&&(y.y<0||x.y>b._worldHeightCurrent))){b.wrapHorizontal||(x.x=Math.max(x.x,0),y.x=Math.min(y.x,b._worldWidthCurrent)),b.wrapVertical||(x.y=Math.max(x.y,0),y.y=Math.min(y.y,b._worldHeightCurrent)),t=Math.min(t,u);var z;for(e=u;e>=t;e--){if(z=!1,g=b.viewport.deltaPixelsFromPoints(b.source.getPixelRatio(e),!0).x*b._scaleSpring.current.value,!p&&g>=b.minPixelRatio||e==t)z=!0,p=!0;else if(!p)continue;if(h=b.viewport.deltaPixelsFromPoints(b.source.getPixelRatio(e),!1).x*b._scaleSpring.current.value,i=b.viewport.deltaPixelsFromPoints(b.source.getPixelRatio(Math.max(b.source.getClosestLevel(b.viewport.containerSize)-1,0)),!1).x*b._scaleSpring.current.value,k=b.immediateRender?1:i,l=Math.min(1,(g-.5)/.5),m=k/Math.abs(k-h),n=c(b,p,z,e,l,m,x,y,q,n),j(b.coverage,e))break}o(b,b.lastDrawn),n&&(f(b,n,q),b._needsDraw=!0)}}function c(a,b,c,e,f,g,h,i,j,k){var l,n,o,p,q,r=a.viewport.pixelFromPoint(a.viewport.getCenter());for(a.viewer&&a.viewer.raiseEvent("update-level",{tiledImage:a,havedrawn:b,level:e,opacity:f,visibility:g,topleft:h,bottomright:i,currenttime:j,best:k}),o=a.source.getTileAtPoint(e,h.divide(a._scaleSpring.current.value)),p=a.source.getTileAtPoint(e,i.divide(a._scaleSpring.current.value)),q=a.source.getNumTiles(e),m(a.coverage,e),a.wrapHorizontal||(p.x=Math.min(p.x,q.x-1)),a.wrapVertical||(p.y=Math.min(p.y,q.y-1)),l=o.x;l<=p.x;l++)for(n=o.y;n<=p.y;n++)k=d(a,c,b,l,n,e,f,g,r,q,j,k);return k}function d(a,b,c,d,f,g,j,m,o,p,q,r){var s=e(d,f,g,a.source,a.tilesMatrix,q,p,a._worldWidthCurrent,a._worldHeightCurrent),t=b;if(a.viewer&&a.viewer.raiseEvent("update-tile",{tiledImage:a,tile:s}),l(a.coverage,g,d,f,!1),!s.exists)return r;if(c&&!t&&(k(a.coverage,g,d,f)?l(a.coverage,g,d,f,!0):t=!0),!t)return r;if(h(s,a.source.tileOverlap,a.viewport,o,m,a),!s.loaded){var u=a._tileCache.getImageRecord(s.url);u&&(s.loaded=!0,s.image=u.getImage(),a._tileCache.cacheTile({tile:s,tiledImage:a}))}if(s.loaded){var v=i(a,s,d,f,g,j,q);v&&(a._needsDraw=!0)}else s.loading||(r=n(r,s));return r}function e(b,c,d,e,f,g,h,i,j){var k,l,m,n,o,p;return f[d]||(f[d]={}),f[d][b]||(f[d][b]={}),f[d][b][c]||(k=(h.x+b%h.x)%h.x,l=(h.y+c%h.y)%h.y,m=e.getTileBounds(d,k,l),n=e.tileExists(d,k,l),o=e.getTileUrl(d,k,l),m.x+=(b-k)/h.x,m.y+=j/i*((c-l)/h.y),f[d][b][c]=new a.Tile(d,b,c,m,n,o)),p=f[d][b][c],p.lastTouchTime=g,p}function f(a,b,c){b.loading=!0,a._imageLoader.addJob({src:b.url,crossOriginPolicy:a.crossOriginPolicy,callback:function(d){g(a,b,c,d)},abort:function(){b.loading=!1}})}function g(b,c,d,e){if(e){if(dh)return!0;return!1}function j(a,b,c,d){var e,f,g,h;if(!a[b])return!1;if(void 0===c||void 0===d){e=a[b];for(g in e)if(e.hasOwnProperty(g)){f=e[g];for(h in f)if(f.hasOwnProperty(h)&&!f[h])return!1}return!0}return void 0===a[b][c]||void 0===a[b][c][d]||a[b][c][d]===!0}function k(a,b,c,d){return void 0===c||void 0===d?j(a,b+1):j(a,b+1,2*c,2*d)&&j(a,b+1,2*c,2*d+1)&&j(a,b+1,2*c+1,2*d)&&j(a,b+1,2*c+1,2*d+1)}function l(b,c,d,e,f){return b[c]?(b[c][d]||(b[c][d]={}),void(b[c][d][e]=f)):void a.console.warn("Setting coverage for a tile before its level's coverage has been reset: %s",c)}function m(a,b){a[b]={}}function n(a,b){return a?b.visibility>a.visibility?b:b.visibility==a.visibility&&b.distance=0;c--)d=b[c],a._drawer.drawTile(d,a._drawingHandler,e),d.beingDrawn=!0,a.viewer&&a.viewer.raiseEvent("tile-drawn",{tiledImage:a,tile:d});f&&a._drawer.restoreContext(e),e&&a._drawer.blendSketch(a.opacity),p(a,b)}function p(b,c){if(b.debugMode)for(var d=c.length-1;d>=0;d--){var e=c[d];try{b._drawer.drawDebugInfo(e,c.length,d)}catch(f){a.console.error(f)}}}a.TiledImage=function(b){var c=this;a.console.assert(b.tileCache,"[TiledImage] options.tileCache is required"),a.console.assert(b.drawer,"[TiledImage] options.drawer is required"),a.console.assert(b.viewer,"[TiledImage] options.viewer is required"),a.console.assert(b.imageLoader,"[TiledImage] options.imageLoader is required"),a.console.assert(b.source,"[TiledImage] options.source is required"),a.console.assert(!b.clip||b.clip instanceof a.Rect,"[TiledImage] options.clip must be an OpenSeadragon.Rect if present"),a.EventSource.call(this),this._tileCache=b.tileCache,delete b.tileCache,this._drawer=b.drawer,delete b.drawer,this._imageLoader=b.imageLoader,delete b.imageLoader,b.clip instanceof a.Rect&&(this._clip=b.clip.clone()),delete b.clip;var d=b.x||0;delete b.x;var e=b.y||0;delete b.y,this.normHeight=b.source.dimensions.y/b.source.dimensions.x,this.contentAspectX=b.source.dimensions.x/b.source.dimensions.y;var f=1;b.width?(f=b.width,delete b.width,b.height&&(a.console.error("specifying both width and height to a tiledImage is not supported"),delete b.height)):b.height&&(f=b.height/this.normHeight,delete b.height),a.extend(!0,this,{viewer:null,tilesMatrix:{},coverage:{},lastDrawn:[],lastResetTime:0,_midDraw:!1,_needsDraw:!0,springStiffness:a.DEFAULT_SETTINGS.springStiffness,animationTime:a.DEFAULT_SETTINGS.animationTime,minZoomImageRatio:a.DEFAULT_SETTINGS.minZoomImageRatio,wrapHorizontal:a.DEFAULT_SETTINGS.wrapHorizontal,wrapVertical:a.DEFAULT_SETTINGS.wrapVertical,immediateRender:a.DEFAULT_SETTINGS.immediateRender,blendTime:a.DEFAULT_SETTINGS.blendTime,alwaysBlend:a.DEFAULT_SETTINGS.alwaysBlend,minPixelRatio:a.DEFAULT_SETTINGS.minPixelRatio,debugMode:a.DEFAULT_SETTINGS.debugMode,crossOriginPolicy:a.DEFAULT_SETTINGS.crossOriginPolicy,placeholderFillStyle:a.DEFAULT_SETTINGS.placeholderFillStyle,opacity:a.DEFAULT_SETTINGS.opacity},b),this._xSpring=new a.Spring({initial:d,springStiffness:this.springStiffness,animationTime:this.animationTime}),this._ySpring=new a.Spring({initial:e,springStiffness:this.springStiffness,animationTime:this.animationTime}),this._scaleSpring=new a.Spring({initial:f,springStiffness:this.springStiffness,animationTime:this.animationTime}),this._updateForScale(),this._drawingHandler=function(b){c.viewer.raiseEvent("tile-drawing",a.extend({tiledImage:c},b))}},a.extend(a.TiledImage.prototype,a.EventSource.prototype,{needsDraw:function(){return this._needsDraw},reset:function(){this._tileCache.clearTilesFor(this),this.lastResetTime=a.now(),this._needsDraw=!0},update:function(){var a=this._xSpring.current.value,b=this._ySpring.current.value,c=this._scaleSpring.current.value;return this._xSpring.update(),this._ySpring.update(),this._scaleSpring.update(),this._xSpring.current.value!==a||this._ySpring.current.value!==b||this._scaleSpring.current.value!==c?(this._updateForScale(),this._needsDraw=!0,!0):!1},draw:function(){this._midDraw=!0,b(this),this._midDraw=!1},destroy:function(){this.reset()},getBounds:function(b){return b?new a.Rect(this._xSpring.current.value,this._ySpring.current.value,this._worldWidthCurrent,this._worldHeightCurrent):new a.Rect(this._xSpring.target.value,this._ySpring.target.value,this._worldWidthTarget,this._worldHeightTarget)},getWorldBounds:function(){return a.console.error("[TiledImage.getWorldBounds] is deprecated; use TiledImage.getBounds instead"),this.getBounds()},getContentSize:function(){return new a.Point(this.source.dimensions.x,this.source.dimensions.y)},_viewportToImageDelta:function(b,c,d){var e=d?this._scaleSpring.current.value:this._scaleSpring.target.value;return new a.Point(b*(this.source.dimensions.x/e),c*(this.source.dimensions.y*this.contentAspectX/e))},viewportToImageCoordinates:function(b,c,d){return b instanceof a.Point&&(d=c,c=b.y,b=b.x),d?this._viewportToImageDelta(b-this._xSpring.current.value,c-this._ySpring.current.value):this._viewportToImageDelta(b-this._xSpring.target.value,c-this._ySpring.target.value)},_imageToViewportDelta:function(b,c,d){var e=d?this._scaleSpring.current.value:this._scaleSpring.target.value;return new a.Point(b/this.source.dimensions.x*e,c/this.source.dimensions.y/this.contentAspectX*e)},imageToViewportCoordinates:function(b,c,d){b instanceof a.Point&&(d=c,c=b.y,b=b.x);var e=this._imageToViewportDelta(b,c);return d?(e.x+=this._xSpring.current.value,e.y+=this._ySpring.current.value):(e.x+=this._xSpring.target.value,e.y+=this._ySpring.target.value),e},imageToViewportRectangle:function(b,c,d,e,f){b instanceof a.Rect&&(f=c,d=b.width,e=b.height,c=b.y,b=b.x);var g=this.imageToViewportCoordinates(b,c,f),h=this._imageToViewportDelta(d,e,f);return new a.Rect(g.x,g.y,h.x,h.y)},viewportToImageRectangle:function(b,c,d,e,f){b instanceof a.Rect&&(f=c,d=b.width,e=b.height,c=b.y,b=b.x);var g=this.viewportToImageCoordinates(b,c,f),h=this._viewportToImageDelta(d,e,f);return new a.Rect(g.x,g.y,h.x,h.y)},setPosition:function(a,b){var c=this._xSpring.target.value===a.x&&this._ySpring.target.value===a.y;if(b){if(c&&this._xSpring.current.value===a.x&&this._ySpring.current.value===a.y)return;this._xSpring.resetTo(a.x),this._ySpring.resetTo(a.y)}else{if(c)return;this._xSpring.springTo(a.x),this._ySpring.springTo(a.y)}c||this._raiseBoundsChange()},setWidth:function(a,b){this._setScale(a,b)},setHeight:function(a,b){this._setScale(a/this.normHeight,b)},getClip:function(){return this._clip?this._clip.clone():null},setClip:function(b){a.console.assert(!b||b instanceof a.Rect,"[TiledImage.setClip] newClip must be an OpenSeadragon.Rect or null"),this._clip=b instanceof a.Rect?b.clone():null,this._needsDraw=!0},getOpacity:function(){return this.opacity},setOpacity:function(a){this.opacity=a,this._needsDraw=!0},_setScale:function(a,b){var c=this._scaleSpring.target.value===a;if(b){if(c&&this._scaleSpring.current.value===a)return;this._scaleSpring.resetTo(a),this._updateForScale()}else{if(c)return;this._scaleSpring.springTo(a),this._updateForScale()}c||this._raiseBoundsChange()},_updateForScale:function(){this._worldWidthTarget=this._scaleSpring.target.value,this._worldHeightTarget=this.normHeight*this._scaleSpring.target.value,this._worldWidthCurrent=this._scaleSpring.current.value,this._worldHeightCurrent=this.normHeight*this._scaleSpring.current.value},_raiseBoundsChange:function(){this.raiseEvent("bounds-change")}})}(OpenSeadragon),function(a){var b=function(b){a.console.assert(b,"[TileCache.cacheTile] options is required"),a.console.assert(b.tile,"[TileCache.cacheTile] options.tile is required"),a.console.assert(b.tiledImage,"[TileCache.cacheTile] options.tiledImage is required"),this.tile=b.tile,this.tiledImage=b.tiledImage},c=function(b){a.console.assert(b,"[ImageRecord] options is required"),a.console.assert(b.image,"[ImageRecord] options.image is required"),this._image=b.image,this._tiles=[]};c.prototype={destroy:function(){this._image=null,this._renderedContext=null,this._tiles=null},getImage:function(){return this._image},getRenderedContext:function(){return this._renderedContext},setRenderedContext:function(a){this._renderedContext=a},addTile:function(b){a.console.assert(b,"[ImageRecord.addTile] tile is required"),this._tiles.push(b)},removeTile:function(b){for(var c=0;cthis._maxImageCacheCount){for(var h,i,j,k,l,m,n=null,o=-1,p=this._tilesLoaded.length-1;p>=0;p--)m=this._tilesLoaded[p],h=m.tile,h.level<=e||h.beingDrawn||(n?(k=h.lastTouchTime,i=n.lastTouchTime,l=h.level,j=n.level,(i>k||k==i&&l>j)&&(n=h,o=p)):(n=h,o=p));n&&o>=0&&(this._unloadTile(n),f=o)}this._tilesLoaded[f]=new b({tile:d.tile,tiledImage:d.tiledImage})},clearTilesFor:function(b){a.console.assert(b,"[TileCache.clearTilesFor] tiledImage is required");for(var c,d=0;d=this._items.length)throw new Error("Index bigger than number of layers.");c!==d&&-1!==d&&(this._items.splice(d,1),this._items.splice(c,0,b),this._needsDraw=!0,this.raiseEvent("item-index-change",{item:b,previousIndex:d,newIndex:c}))},removeItem:function(b){a.console.assert(b,"[World.removeItem] item is required");var c=a.indexOf(this._items,b);-1!==c&&(b.removeHandler("bounds-change",this._delegatedFigureSizes),b.destroy(),this._items.splice(c,1),this._figureSizes(),this._needsDraw=!0,this._raiseRemoveItem(b))},removeAll:function(){for(var a,b=0;bd.height?k:k*(d.width/d.height),f=e*(d.height/d.width),g=new a.Point(o+(k-e)/2,p+(k-f)/2),c.setPosition(g,h),c.setWidth(e,h),"horizontal"===i?o+=m:p+=m},_figureSizes:function(){var b=this._homeBounds?this._homeBounds.clone():null,c=this._contentSize?this._contentSize.clone():null,d=this._contentFactor||0;if(this._items.length){var e=this._items[0].getBounds();this._contentFactor=this._items[0].getContentSize().x/e.width;for(var f,g=e.x,h=e.y,i=e.x+e.width,j=e.y+e.height,k=1;kDEPRECATED. A relative path to load a DZI file from the server. + * Prefer the newer Options.tileSources. + * + * @property {String} [prefixUrl='/images/'] + * Prepends the prefixUrl to navImages paths, which is very useful + * since the default paths are rarely useful for production + * environments. + * + * @property {OpenSeadragon.NavImages} [navImages] + * An object with a property for each button or other built-in navigation + * control, eg the current 'zoomIn', 'zoomOut', 'home', and 'fullpage'. + * Each of those in turn provides an image path for each state of the button + * or navigation control, eg 'REST', 'GROUP', 'HOVER', 'PRESS'. Finally the + * image paths, by default assume there is a folder on the servers root path + * called '/images', eg '/images/zoomin_rest.png'. If you need to adjust + * these paths, prefer setting the option.prefixUrl rather than overriding + * every image path directly through this setting. + * + * @property {Boolean} [debugMode=false] + * TODO: provide an in-screen panel providing event detail feedback. + * + * @property {String} [debugGridColor=['#437AB2', '#1B9E77', '#D95F02', '#7570B3', '#E7298A', '#66A61E', '#E6AB02', '#A6761D', '#666666']] + * The colors of grids in debug mode. Each tiled image's grid uses a consecutive color. + * If there are more tiled images than provided colors, the color vector is recycled. + * + * @property {Number} [blendTime=0] + * Specifies the duration of animation as higher or lower level tiles are + * replacing the existing tile. + * + * @property {Boolean} [alwaysBlend=false] + * Forces the tile to always blend. By default the tiles skip blending + * when the blendTime is surpassed and the current animation frame would + * not complete the blend. + * + * @property {Boolean} [autoHideControls=true] + * If the user stops interacting with the viewport, fade the navigation + * controls. Useful for presentation since the controls are by default + * floated on top of the image the user is viewing. + * + * @property {Boolean} [immediateRender=false] + * Render the best closest level first, ignoring the lowering levels which + * provide the effect of very blurry to sharp. It is recommended to change + * setting to true for mobile devices. + * + * @property {Number} [defaultZoomLevel=0] + * Zoom level to use when image is first opened or the home button is clicked. + * If 0, adjusts to fit viewer. + * + * @property {Number} [opacity=1] + * Default proportional opacity of the tiled images (1=opaque, 0=hidden) + * Hidden images do not draw and only load when preloading is allowed. + * + * @property {Boolean} [preload=false] + * Default switch for loading hidden images (true loads, false blocks) + * + * @property {String} [compositeOperation=null] + * Valid values are 'source-over', 'source-atop', 'source-in', 'source-out', + * 'destination-over', 'destination-atop', 'destination-in', + * 'destination-out', 'lighter', 'copy' or 'xor' + * + * @property {String|CanvasGradient|CanvasPattern|Function} [placeholderFillStyle=null] + * Draws a colored rectangle behind the tile if it is not loaded yet. + * You can pass a CSS color value like "#FF8800". + * When passing a function the tiledImage and canvas context are available as argument which is useful when you draw a gradient or pattern. + * + * @property {Number} [degrees=0] + * Initial rotation. + * + * @property {Number} [minZoomLevel=null] + * + * @property {Number} [maxZoomLevel=null] + * + * @property {Boolean} [homeFillsViewer=false] + * Make the 'home' button fill the viewer and clip the image, instead + * of fitting the image to the viewer and letterboxing. + * + * @property {Boolean} [panHorizontal=true] + * Allow horizontal pan. + * + * @property {Boolean} [panVertical=true] + * Allow vertical pan. + * + * @property {Boolean} [constrainDuringPan=false] + * + * @property {Boolean} [wrapHorizontal=false] + * Set to true to force the image to wrap horizontally within the viewport. + * Useful for maps or images representing the surface of a sphere or cylinder. + * + * @property {Boolean} [wrapVertical=false] + * Set to true to force the image to wrap vertically within the viewport. + * Useful for maps or images representing the surface of a sphere or cylinder. + * + * @property {Number} [minZoomImageRatio=0.9] + * The minimum percentage ( expressed as a number between 0 and 1 ) of + * the viewport height or width at which the zoom out will be constrained. + * Setting it to 0, for example will allow you to zoom out infinity. + * + * @property {Number} [maxZoomPixelRatio=1.1] + * The maximum ratio to allow a zoom-in to affect the highest level pixel + * ratio. This can be set to Infinity to allow 'infinite' zooming into the + * image though it is less effective visually if the HTML5 Canvas is not + * availble on the viewing device. + * + * @property {Number} [smoothTileEdgesMinZoom=1.1] + * A zoom percentage ( where 1 is 100% ) of the highest resolution level. + * When zoomed in beyond this value alternative compositing will be used to + * smooth out the edges between tiles. This will have a performance impact. + * Can be set to Infinity to turn it off. + * Note: This setting is ignored on iOS devices due to a known bug (See {@link https://github.com/openseadragon/openseadragon/issues/952}) + * + * @property {Boolean} [iOSDevice=?] + * True if running on an iOS device, false otherwise. + * Used to disable certain features that behave differently on iOS devices. + * + * @property {Boolean} [autoResize=true] + * Set to false to prevent polling for viewer size changes. Useful for providing custom resize behavior. + * + * @property {Boolean} [preserveImageSizeOnResize=false] + * Set to true to have the image size preserved when the viewer is resized. This requires autoResize=true (default). + * + * @property {Number} [minScrollDeltaTime=50] + * Number of milliseconds between canvas-scroll events. This value helps normalize the rate of canvas-scroll + * events between different devices, causing the faster devices to slow down enough to make the zoom control + * more manageable. + * + * @property {Number} [pixelsPerWheelLine=40] + * For pixel-resolution scrolling devices, the number of pixels equal to one scroll line. + * + * @property {Number} [visibilityRatio=0.5] + * The percentage ( as a number from 0 to 1 ) of the source image which + * must be kept within the viewport. If the image is dragged beyond that + * limit, it will 'bounce' back until the minimum visibility ratio is + * achieved. Setting this to 0 and wrapHorizontal ( or wrapVertical ) to + * true will provide the effect of an infinitely scrolling viewport. + * + * @property {Object} [viewportMargins={}] + * Pushes the "home" region in from the sides by the specified amounts. + * Possible subproperties (Numbers, in screen coordinates): left, top, right, bottom. + * + * @property {Number} [imageLoaderLimit=0] + * The maximum number of image requests to make concurrently. By default + * it is set to 0 allowing the browser to make the maximum number of + * image requests in parallel as allowed by the browsers policy. + * + * @property {Number} [clickTimeThreshold=300] + * The number of milliseconds within which a pointer down-up event combination + * will be treated as a click gesture. + * + * @property {Number} [clickDistThreshold=5] + * The maximum distance allowed between a pointer down event and a pointer up event + * to be treated as a click gesture. + * + * @property {Number} [dblClickTimeThreshold=300] + * The number of milliseconds within which two pointer down-up event combinations + * will be treated as a double-click gesture. + * + * @property {Number} [dblClickDistThreshold=20] + * The maximum distance allowed between two pointer click events + * to be treated as a double-click gesture. + * + * @property {Number} [springStiffness=6.5] + * + * @property {Number} [animationTime=1.2] + * Specifies the animation duration per each {@link OpenSeadragon.Spring} + * which occur when the image is dragged or zoomed. + * + * @property {OpenSeadragon.GestureSettings} [gestureSettingsMouse] + * Settings for gestures generated by a mouse pointer device. (See {@link OpenSeadragon.GestureSettings}) + * @property {Boolean} [gestureSettingsMouse.scrollToZoom=true] - Zoom on scroll gesture + * @property {Boolean} [gestureSettingsMouse.clickToZoom=true] - Zoom on click gesture + * @property {Boolean} [gestureSettingsMouse.dblClickToZoom=false] - Zoom on double-click gesture. Note: If set to true + * then clickToZoom should be set to false to prevent multiple zooms. + * @property {Boolean} [gestureSettingsMouse.pinchToZoom=false] - Zoom on pinch gesture + * @property {Boolean} [gestureSettingsMouse.flickEnabled=false] - Enable flick gesture + * @property {Number} [gestureSettingsMouse.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second) + * @property {Number} [gestureSettingsMouse.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture + * @property {Boolean} [gestureSettingsMouse.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers. + * + * @property {OpenSeadragon.GestureSettings} [gestureSettingsTouch] + * Settings for gestures generated by a touch pointer device. (See {@link OpenSeadragon.GestureSettings}) + * @property {Boolean} [gestureSettingsTouch.scrollToZoom=false] - Zoom on scroll gesture + * @property {Boolean} [gestureSettingsTouch.clickToZoom=false] - Zoom on click gesture + * @property {Boolean} [gestureSettingsTouch.dblClickToZoom=true] - Zoom on double-click gesture. Note: If set to true + * then clickToZoom should be set to false to prevent multiple zooms. + * @property {Boolean} [gestureSettingsTouch.pinchToZoom=true] - Zoom on pinch gesture + * @property {Boolean} [gestureSettingsTouch.flickEnabled=true] - Enable flick gesture + * @property {Number} [gestureSettingsTouch.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second) + * @property {Number} [gestureSettingsTouch.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture + * @property {Boolean} [gestureSettingsTouch.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers. + * + * @property {OpenSeadragon.GestureSettings} [gestureSettingsPen] + * Settings for gestures generated by a pen pointer device. (See {@link OpenSeadragon.GestureSettings}) + * @property {Boolean} [gestureSettingsPen.scrollToZoom=false] - Zoom on scroll gesture + * @property {Boolean} [gestureSettingsPen.clickToZoom=true] - Zoom on click gesture + * @property {Boolean} [gestureSettingsPen.dblClickToZoom=false] - Zoom on double-click gesture. Note: If set to true + * then clickToZoom should be set to false to prevent multiple zooms. + * @property {Boolean} [gestureSettingsPen.pinchToZoom=false] - Zoom on pinch gesture + * @property {Boolean} [gestureSettingsPen.flickEnabled=false] - Enable flick gesture + * @property {Number} [gestureSettingsPen.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second) + * @property {Number} [gestureSettingsPen.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture + * @property {Boolean} [gestureSettingsPen.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers. + * + * @property {OpenSeadragon.GestureSettings} [gestureSettingsUnknown] + * Settings for gestures generated by unknown pointer devices. (See {@link OpenSeadragon.GestureSettings}) + * @property {Boolean} [gestureSettingsUnknown.scrollToZoom=true] - Zoom on scroll gesture + * @property {Boolean} [gestureSettingsUnknown.clickToZoom=false] - Zoom on click gesture + * @property {Boolean} [gestureSettingsUnknown.dblClickToZoom=true] - Zoom on double-click gesture. Note: If set to true + * then clickToZoom should be set to false to prevent multiple zooms. + * @property {Boolean} [gestureSettingsUnknown.pinchToZoom=true] - Zoom on pinch gesture + * @property {Boolean} [gestureSettingsUnknown.flickEnabled=true] - Enable flick gesture + * @property {Number} [gestureSettingsUnknown.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second) + * @property {Number} [gestureSettingsUnknown.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture + * @property {Boolean} [gestureSettingsUnknown.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers. + * + * @property {Number} [zoomPerClick=2.0] + * The "zoom distance" per mouse click or touch tap. Note: Setting this to 1.0 effectively disables the click-to-zoom feature (also see gestureSettings[Mouse|Touch|Pen].clickToZoom/dblClickToZoom). + * + * @property {Number} [zoomPerScroll=1.2] + * The "zoom distance" per mouse scroll or touch pinch. Note: Setting this to 1.0 effectively disables the mouse-wheel zoom feature (also see gestureSettings[Mouse|Touch|Pen].scrollToZoom}). + * + * @property {Number} [zoomPerSecond=1.0] + * The number of seconds to animate a single zoom event over. + * + * @property {Boolean} [showNavigator=false] + * Set to true to make the navigator minimap appear. + * + * @property {String} [navigatorId=navigator-GENERATED DATE] + * The ID of a div to hold the navigator minimap. + * If an ID is specified, the navigatorPosition, navigatorSizeRatio, navigatorMaintainSizeRatio, navigator[Top|Left|Height|Width] and navigatorAutoFade options will be ignored. + * If an ID is not specified, a div element will be generated and placed on top of the main image. + * + * @property {String} [navigatorPosition='TOP_RIGHT'] + * Valid values are 'TOP_LEFT', 'TOP_RIGHT', 'BOTTOM_LEFT', 'BOTTOM_RIGHT', or 'ABSOLUTE'.
      + * If 'ABSOLUTE' is specified, then navigator[Top|Left|Height|Width] determines the size and position of the navigator minimap in the viewer, and navigatorSizeRatio and navigatorMaintainSizeRatio are ignored.
      + * For 'TOP_LEFT', 'TOP_RIGHT', 'BOTTOM_LEFT', and 'BOTTOM_RIGHT', the navigatorSizeRatio or navigator[Height|Width] values determine the size of the navigator minimap. + * + * @property {Number} [navigatorSizeRatio=0.2] + * Ratio of navigator size to viewer size. Ignored if navigator[Height|Width] are specified. + * + * @property {Boolean} [navigatorMaintainSizeRatio=false] + * If true, the navigator minimap is resized (using navigatorSizeRatio) when the viewer size changes. + * + * @property {Number|String} [navigatorTop=null] + * Specifies the location of the navigator minimap (see navigatorPosition). + * + * @property {Number|String} [navigatorLeft=null] + * Specifies the location of the navigator minimap (see navigatorPosition). + * + * @property {Number|String} [navigatorHeight=null] + * Specifies the size of the navigator minimap (see navigatorPosition). + * If specified, navigatorSizeRatio and navigatorMaintainSizeRatio are ignored. + * + * @property {Number|String} [navigatorWidth=null] + * Specifies the size of the navigator minimap (see navigatorPosition). + * If specified, navigatorSizeRatio and navigatorMaintainSizeRatio are ignored. + * + * @property {Boolean} [navigatorAutoResize=true] + * Set to false to prevent polling for navigator size changes. Useful for providing custom resize behavior. + * Setting to false can also improve performance when the navigator is configured to a fixed size. + * + * @property {Boolean} [navigatorAutoFade=true] + * If the user stops interacting with the viewport, fade the navigator minimap. + * Setting to false will make the navigator minimap always visible. + * + * @property {Boolean} [navigatorRotate=true] + * If true, the navigator will be rotated together with the viewer. + * + * @property {Number} [controlsFadeDelay=2000] + * The number of milliseconds to wait once the user has stopped interacting + * with the interface before begining to fade the controls. Assumes + * showNavigationControl and autoHideControls are both true. + * + * @property {Number} [controlsFadeLength=1500] + * The number of milliseconds to animate the controls fading out. + * + * @property {Number} [maxImageCacheCount=200] + * The max number of images we should keep in memory (per drawer). + * + * @property {Number} [timeout=30000] + * The max number of milliseconds that an image job may take to complete. + * + * @property {Boolean} [useCanvas=true] + * Set to false to not use an HTML canvas element for image rendering even if canvas is supported. + * + * @property {Number} [minPixelRatio=0.5] + * The higher the minPixelRatio, the lower the quality of the image that + * is considered sufficient to stop rendering a given zoom level. For + * example, if you are targeting mobile devices with less bandwith you may + * try setting this to 1.5 or higher. + * + * @property {Boolean} [mouseNavEnabled=true] + * Is the user able to interact with the image via mouse or touch. Default + * interactions include draging the image in a plane, and zooming in toward + * and away from the image. + * + * @property {Boolean} [showNavigationControl=true] + * Set to false to prevent the appearance of the default navigation controls.
      + * Note that if set to false, the customs buttons set by the options + * zoomInButton, zoomOutButton etc, are rendered inactive. + * + * @property {OpenSeadragon.ControlAnchor} [navigationControlAnchor=TOP_LEFT] + * Placement of the default navigation controls. + * To set the placement of the sequence controls, see the + * sequenceControlAnchor option. + * + * @property {Boolean} [showZoomControl=true] + * If true then + and - buttons to zoom in and out are displayed.
      + * Note: {@link OpenSeadragon.Options.showNavigationControl} is overriding + * this setting when set to false. + * + * @property {Boolean} [showHomeControl=true] + * If true then the 'Go home' button is displayed to go back to the original + * zoom and pan.
      + * Note: {@link OpenSeadragon.Options.showNavigationControl} is overriding + * this setting when set to false. + * + * @property {Boolean} [showFullPageControl=true] + * If true then the 'Toggle full page' button is displayed to switch + * between full page and normal mode.
      + * Note: {@link OpenSeadragon.Options.showNavigationControl} is overriding + * this setting when set to false. + * + * @property {Boolean} [showRotationControl=false] + * If true then the rotate left/right controls will be displayed as part of the + * standard controls. This is also subject to the browser support for rotate + * (e.g. viewer.drawer.canRotate()).
      + * Note: {@link OpenSeadragon.Options.showNavigationControl} is overriding + * this setting when set to false. + * + * @property {Boolean} [showSequenceControl=true] + * If sequenceMode is true, then provide buttons for navigating forward and + * backward through the images. + * + * @property {OpenSeadragon.ControlAnchor} [sequenceControlAnchor=TOP_LEFT] + * Placement of the default sequence controls. + * + * @property {Boolean} [navPrevNextWrap=false] + * If true then the 'previous' button will wrap to the last image when + * viewing the first image and the 'next' button will wrap to the first + * image when viewing the last image. + * + * @property {String} zoomInButton + * Set the id of the custom 'Zoom in' button to use. + * This is useful to have a custom button anywhere in the web page.
      + * To only change the button images, consider using + * {@link OpenSeadragon.Options.navImages} + * + * @property {String} zoomOutButton + * Set the id of the custom 'Zoom out' button to use. + * This is useful to have a custom button anywhere in the web page.
      + * To only change the button images, consider using + * {@link OpenSeadragon.Options.navImages} + * + * @property {String} homeButton + * Set the id of the custom 'Go home' button to use. + * This is useful to have a custom button anywhere in the web page.
      + * To only change the button images, consider using + * {@link OpenSeadragon.Options.navImages} + * + * @property {String} fullPageButton + * Set the id of the custom 'Toggle full page' button to use. + * This is useful to have a custom button anywhere in the web page.
      + * To only change the button images, consider using + * {@link OpenSeadragon.Options.navImages} + * + * @property {String} rotateLeftButton + * Set the id of the custom 'Rotate left' button to use. + * This is useful to have a custom button anywhere in the web page.
      + * To only change the button images, consider using + * {@link OpenSeadragon.Options.navImages} + * + * @property {String} rotateRightButton + * Set the id of the custom 'Rotate right' button to use. + * This is useful to have a custom button anywhere in the web page.
      + * To only change the button images, consider using + * {@link OpenSeadragon.Options.navImages} + * + * @property {String} previousButton + * Set the id of the custom 'Previous page' button to use. + * This is useful to have a custom button anywhere in the web page.
      + * To only change the button images, consider using + * {@link OpenSeadragon.Options.navImages} + * + * @property {String} nextButton + * Set the id of the custom 'Next page' button to use. + * This is useful to have a custom button anywhere in the web page.
      + * To only change the button images, consider using + * {@link OpenSeadragon.Options.navImages} + * + * @property {Boolean} [sequenceMode=false] + * Set to true to have the viewer treat your tilesources as a sequence of images to + * be opened one at a time rather than all at once. + * + * @property {Number} [initialPage=0] + * If sequenceMode is true, display this page initially. + * + * @property {Boolean} [preserveViewport=false] + * If sequenceMode is true, then normally navigating through each image resets the + * viewport to 'home' position. If preserveViewport is set to true, then the viewport + * position is preserved when navigating between images in the sequence. + * + * @property {Boolean} [preserveOverlays=false] + * If sequenceMode is true, then normally navigating through each image + * resets the overlays. + * If preserveOverlays is set to true, then the overlays added with {@link OpenSeadragon.Viewer#addOverlay} + * are preserved when navigating between images in the sequence. + * Note: setting preserveOverlays overrides any overlays specified in the global + * "overlays" option for the Viewer. It's also not compatible with specifying + * per-tileSource overlays via the options, as those overlays will persist + * even after the tileSource is closed. + * + * @property {Boolean} [showReferenceStrip=false] + * If sequenceMode is true, then display a scrolling strip of image thumbnails for + * navigating through the images. + * + * @property {String} [referenceStripScroll='horizontal'] + * + * @property {Element} [referenceStripElement=null] + * + * @property {Number} [referenceStripHeight=null] + * + * @property {Number} [referenceStripWidth=null] + * + * @property {String} [referenceStripPosition='BOTTOM_LEFT'] + * + * @property {Number} [referenceStripSizeRatio=0.2] + * + * @property {Boolean} [collectionMode=false] + * Set to true to have the viewer arrange your TiledImages in a grid or line. + * + * @property {Number} [collectionRows=3] + * If collectionMode is true, specifies how many rows the grid should have. Use 1 to make a line. + * If collectionLayout is 'vertical', specifies how many columns instead. + * + * @property {Number} [collectionColumns=0] + * If collectionMode is true, specifies how many columns the grid should have. Use 1 to make a line. + * If collectionLayout is 'vertical', specifies how many rows instead. Ignored if collectionRows is not set to a falsy value. + * + * @property {String} [collectionLayout='horizontal'] + * If collectionMode is true, specifies whether to arrange vertically or horizontally. + * + * @property {Number} [collectionTileSize=800] + * If collectionMode is true, specifies the size, in viewport coordinates, for each TiledImage to fit into. + * The TiledImage will be centered within a square of the specified size. + * + * @property {Number} [collectionTileMargin=80] + * If collectionMode is true, specifies the margin, in viewport coordinates, between each TiledImage. + * + * @property {String|Boolean} [crossOriginPolicy=false] + * Valid values are 'Anonymous', 'use-credentials', and false. If false, canvas requests will + * not use CORS, and the canvas will be tainted. + * + * @property {Boolean} [ajaxWithCredentials=false] + * Whether to set the withCredentials XHR flag for AJAX requests. + * Note that this can be overridden at the {@link OpenSeadragon.TileSource} level. + * + * @property {Boolean} [loadTilesWithAjax=false] + * Whether to load tile data using AJAX requests. + * Note that this can be overridden at the {@link OpenSeadragon.TileSource} level. + * + * @property {Object} [ajaxHeaders={}] + * A set of headers to include when making AJAX requests for tile sources or tiles. + * + */ + + /** + * Settings for gestures generated by a pointer device. + * + * @typedef {Object} GestureSettings + * @memberof OpenSeadragon + * + * @property {Boolean} scrollToZoom + * Set to false to disable zooming on scroll gestures. + * + * @property {Boolean} clickToZoom + * Set to false to disable zooming on click gestures. + * + * @property {Boolean} dblClickToZoom + * Set to false to disable zooming on double-click gestures. Note: If set to true + * then clickToZoom should be set to false to prevent multiple zooms. + * + * @property {Boolean} pinchToZoom + * Set to false to disable zooming on pinch gestures. + * + * @property {Boolean} flickEnabled + * Set to false to disable the kinetic panning effect (flick) at the end of a drag gesture. + * + * @property {Number} flickMinSpeed + * If flickEnabled is true, the minimum speed (in pixels-per-second) required to cause the kinetic panning effect (flick) at the end of a drag gesture. + * + * @property {Number} flickMomentum + * If flickEnabled is true, a constant multiplied by the velocity to determine the distance of the kinetic panning effect (flick) at the end of a drag gesture. + * A larger value will make the flick feel "lighter", while a smaller value will make the flick feel "heavier". + * Note: springStiffness and animationTime also affect the "spring" used to stop the flick animation. + * + */ + +/** + * The names for the image resources used for the image navigation buttons. + * + * @typedef {Object} NavImages + * @memberof OpenSeadragon + * + * @property {Object} zoomIn - Images for the zoom-in button. + * @property {String} zoomIn.REST + * @property {String} zoomIn.GROUP + * @property {String} zoomIn.HOVER + * @property {String} zoomIn.DOWN + * + * @property {Object} zoomOut - Images for the zoom-out button. + * @property {String} zoomOut.REST + * @property {String} zoomOut.GROUP + * @property {String} zoomOut.HOVER + * @property {String} zoomOut.DOWN + * + * @property {Object} home - Images for the home button. + * @property {String} home.REST + * @property {String} home.GROUP + * @property {String} home.HOVER + * @property {String} home.DOWN + * + * @property {Object} fullpage - Images for the full-page button. + * @property {String} fullpage.REST + * @property {String} fullpage.GROUP + * @property {String} fullpage.HOVER + * @property {String} fullpage.DOWN + * + * @property {Object} rotateleft - Images for the rotate left button. + * @property {String} rotateleft.REST + * @property {String} rotateleft.GROUP + * @property {String} rotateleft.HOVER + * @property {String} rotateleft.DOWN + * + * @property {Object} rotateright - Images for the rotate right button. + * @property {String} rotateright.REST + * @property {String} rotateright.GROUP + * @property {String} rotateright.HOVER + * @property {String} rotateright.DOWN + * + * @property {Object} previous - Images for the previous button. + * @property {String} previous.REST + * @property {String} previous.GROUP + * @property {String} previous.HOVER + * @property {String} previous.DOWN + * + * @property {Object} next - Images for the next button. + * @property {String} next.REST + * @property {String} next.GROUP + * @property {String} next.HOVER + * @property {String} next.DOWN + * + */ + + +function OpenSeadragon( options ){ + return new OpenSeadragon.Viewer( options ); +} + +(function( $ ){ + + + /** + * The OpenSeadragon version. + * + * @member {Object} OpenSeadragon.version + * @property {String} versionStr - The version number as a string ('major.minor.revision'). + * @property {Number} major - The major version number. + * @property {Number} minor - The minor version number. + * @property {Number} revision - The revision number. + * @since 1.0.0 + */ + $.version = { + versionStr: '2.3.1', + major: parseInt('2', 10), + minor: parseInt('3', 10), + revision: parseInt('1', 10) + }; + + + /** + * Taken from jquery 1.6.1 + * [[Class]] -> type pairs + * @private + */ + var class2type = { + '[object Boolean]': 'boolean', + '[object Number]': 'number', + '[object String]': 'string', + '[object Function]': 'function', + '[object Array]': 'array', + '[object Date]': 'date', + '[object RegExp]': 'regexp', + '[object Object]': 'object' + }, + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty; + + /** + * Taken from jQuery 1.6.1 + * @function isFunction + * @memberof OpenSeadragon + * @see {@link http://www.jquery.com/ jQuery} + */ + $.isFunction = function( obj ) { + return $.type(obj) === "function"; + }; + + + /** + * Taken from jQuery 1.6.1 + * @function isArray + * @memberof OpenSeadragon + * @see {@link http://www.jquery.com/ jQuery} + */ + $.isArray = Array.isArray || function( obj ) { + return $.type(obj) === "array"; + }; + + + /** + * A crude way of determining if an object is a window. + * Taken from jQuery 1.6.1 + * @function isWindow + * @memberof OpenSeadragon + * @see {@link http://www.jquery.com/ jQuery} + */ + $.isWindow = function( obj ) { + return obj && typeof obj === "object" && "setInterval" in obj; + }; + + + /** + * Taken from jQuery 1.6.1 + * @function type + * @memberof OpenSeadragon + * @see {@link http://www.jquery.com/ jQuery} + */ + $.type = function( obj ) { + return ( obj === null ) || ( obj === undefined ) ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }; + + + /** + * Taken from jQuery 1.6.1 + * @function isPlainObject + * @memberof OpenSeadragon + * @see {@link http://www.jquery.com/ jQuery} + */ + $.isPlainObject = function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || OpenSeadragon.type(obj) !== "object" || obj.nodeType || $.isWindow( obj ) ) { + return false; + } + + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var lastKey; + for (var key in obj ) { + lastKey = key; + } + + return lastKey === undefined || hasOwn.call( obj, lastKey ); + }; + + + /** + * Taken from jQuery 1.6.1 + * @function isEmptyObject + * @memberof OpenSeadragon + * @see {@link http://www.jquery.com/ jQuery} + */ + $.isEmptyObject = function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }; + + /** + * Shim around Object.freeze. Does nothing if Object.freeze is not supported. + * @param {Object} obj The object to freeze. + * @return {Object} obj The frozen object. + */ + $.freezeObject = function(obj) { + if (Object.freeze) { + $.freezeObject = Object.freeze; + } else { + $.freezeObject = function(obj) { + return obj; + }; + } + return $.freezeObject(obj); + }; + + /** + * True if the browser supports the HTML5 canvas element + * @member {Boolean} supportsCanvas + * @memberof OpenSeadragon + */ + $.supportsCanvas = (function () { + var canvasElement = document.createElement( 'canvas' ); + return !!( $.isFunction( canvasElement.getContext ) && + canvasElement.getContext( '2d' ) ); + }()); + + /** + * Test whether the submitted canvas is tainted or not. + * @argument {Canvas} canvas The canvas to test. + * @returns {Boolean} True if the canvas is tainted. + */ + $.isCanvasTainted = function(canvas) { + var isTainted = false; + try { + // We test if the canvas is tainted by retrieving data from it. + // An exception will be raised if the canvas is tainted. + canvas.getContext('2d').getImageData(0, 0, 1, 1); + } catch (e) { + isTainted = true; + } + return isTainted; + }; + + /** + * A ratio comparing the device screen's pixel density to the canvas's backing store pixel density, + * clamped to a minimum of 1. Defaults to 1 if canvas isn't supported by the browser. + * @member {Number} pixelDensityRatio + * @memberof OpenSeadragon + */ + $.pixelDensityRatio = (function () { + if ( $.supportsCanvas ) { + var context = document.createElement('canvas').getContext('2d'); + var devicePixelRatio = window.devicePixelRatio || 1; + var backingStoreRatio = context.webkitBackingStorePixelRatio || + context.mozBackingStorePixelRatio || + context.msBackingStorePixelRatio || + context.oBackingStorePixelRatio || + context.backingStorePixelRatio || 1; + return Math.max(devicePixelRatio, 1) / backingStoreRatio; + } else { + return 1; + } + }()); + +}( OpenSeadragon )); + +/** + * This closure defines all static methods available to the OpenSeadragon + * namespace. Many, if not most, are taked directly from jQuery for use + * to simplify and reduce common programming patterns. More static methods + * from jQuery may eventually make their way into this though we are + * attempting to avoid an explicit dependency on jQuery only because + * OpenSeadragon is a broadly useful code base and would be made less broad + * by requiring jQuery fully. + * + * Some static methods have also been refactored from the original OpenSeadragon + * project. + */ +(function( $ ){ + + /** + * Taken from jQuery 1.6.1 + * @function extend + * @memberof OpenSeadragon + * @see {@link http://www.jquery.com/ jQuery} + */ + $.extend = function() { + var options, + name, + src, + copy, + copyIsArray, + clone, + target = arguments[ 0 ] || {}, + length = arguments.length, + deep = false, + i = 1; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[ 1 ] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !OpenSeadragon.isFunction( target ) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + options = arguments[ i ]; + if ( options !== null || options !== undefined ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( OpenSeadragon.isPlainObject( copy ) || ( copyIsArray = OpenSeadragon.isArray( copy ) ) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && OpenSeadragon.isArray( src ) ? src : []; + + } else { + clone = src && OpenSeadragon.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = OpenSeadragon.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; + }; + + var isIOSDevice = function () { + if (typeof navigator !== 'object') { + return false; + } + var userAgent = navigator.userAgent; + if (typeof userAgent !== 'string') { + return false; + } + return userAgent.indexOf('iPhone') !== -1 || + userAgent.indexOf('iPad') !== -1 || + userAgent.indexOf('iPod') !== -1; + }; + + $.extend( $, /** @lends OpenSeadragon */{ + /** + * The default values for the optional settings documented at {@link OpenSeadragon.Options}. + * @static + * @type {Object} + */ + DEFAULT_SETTINGS: { + //DATA SOURCE DETAILS + xmlPath: null, + tileSources: null, + tileHost: null, + initialPage: 0, + crossOriginPolicy: false, + ajaxWithCredentials: false, + loadTilesWithAjax: false, + ajaxHeaders: {}, + + //PAN AND ZOOM SETTINGS AND CONSTRAINTS + panHorizontal: true, + panVertical: true, + constrainDuringPan: false, + wrapHorizontal: false, + wrapVertical: false, + visibilityRatio: 0.5, //-> how much of the viewer can be negative space + minPixelRatio: 0.5, //->closer to 0 draws tiles meant for a higher zoom at this zoom + defaultZoomLevel: 0, + minZoomLevel: null, + maxZoomLevel: null, + homeFillsViewer: false, + + //UI RESPONSIVENESS AND FEEL + clickTimeThreshold: 300, + clickDistThreshold: 5, + dblClickTimeThreshold: 300, + dblClickDistThreshold: 20, + springStiffness: 6.5, + animationTime: 1.2, + gestureSettingsMouse: { + scrollToZoom: true, + clickToZoom: true, + dblClickToZoom: false, + pinchToZoom: false, + flickEnabled: false, + flickMinSpeed: 120, + flickMomentum: 0.25, + pinchRotate: false + }, + gestureSettingsTouch: { + scrollToZoom: false, + clickToZoom: false, + dblClickToZoom: true, + pinchToZoom: true, + flickEnabled: true, + flickMinSpeed: 120, + flickMomentum: 0.25, + pinchRotate: false + }, + gestureSettingsPen: { + scrollToZoom: false, + clickToZoom: true, + dblClickToZoom: false, + pinchToZoom: false, + flickEnabled: false, + flickMinSpeed: 120, + flickMomentum: 0.25, + pinchRotate: false + }, + gestureSettingsUnknown: { + scrollToZoom: false, + clickToZoom: false, + dblClickToZoom: true, + pinchToZoom: true, + flickEnabled: true, + flickMinSpeed: 120, + flickMomentum: 0.25, + pinchRotate: false + }, + zoomPerClick: 2, + zoomPerScroll: 1.2, + zoomPerSecond: 1.0, + blendTime: 0, + alwaysBlend: false, + autoHideControls: true, + immediateRender: false, + minZoomImageRatio: 0.9, //-> closer to 0 allows zoom out to infinity + maxZoomPixelRatio: 1.1, //-> higher allows 'over zoom' into pixels + smoothTileEdgesMinZoom: 1.1, //-> higher than maxZoomPixelRatio disables it + iOSDevice: isIOSDevice(), + pixelsPerWheelLine: 40, + autoResize: true, + preserveImageSizeOnResize: false, // requires autoResize=true + minScrollDeltaTime: 50, + + //DEFAULT CONTROL SETTINGS + showSequenceControl: true, //SEQUENCE + sequenceControlAnchor: null, //SEQUENCE + preserveViewport: false, //SEQUENCE + preserveOverlays: false, //SEQUENCE + navPrevNextWrap: false, //SEQUENCE + showNavigationControl: true, //ZOOM/HOME/FULL/ROTATION + navigationControlAnchor: null, //ZOOM/HOME/FULL/ROTATION + showZoomControl: true, //ZOOM + showHomeControl: true, //HOME + showFullPageControl: true, //FULL + showRotationControl: false, //ROTATION + controlsFadeDelay: 2000, //ZOOM/HOME/FULL/SEQUENCE + controlsFadeLength: 1500, //ZOOM/HOME/FULL/SEQUENCE + mouseNavEnabled: true, //GENERAL MOUSE INTERACTIVITY + + //VIEWPORT NAVIGATOR SETTINGS + showNavigator: false, + navigatorId: null, + navigatorPosition: null, + navigatorSizeRatio: 0.2, + navigatorMaintainSizeRatio: false, + navigatorTop: null, + navigatorLeft: null, + navigatorHeight: null, + navigatorWidth: null, + navigatorAutoResize: true, + navigatorAutoFade: true, + navigatorRotate: true, + + // INITIAL ROTATION + degrees: 0, + + // APPEARANCE + opacity: 1, + preload: false, + compositeOperation: null, + placeholderFillStyle: null, + + //REFERENCE STRIP SETTINGS + showReferenceStrip: false, + referenceStripScroll: 'horizontal', + referenceStripElement: null, + referenceStripHeight: null, + referenceStripWidth: null, + referenceStripPosition: 'BOTTOM_LEFT', + referenceStripSizeRatio: 0.2, + + //COLLECTION VISUALIZATION SETTINGS + collectionRows: 3, //or columns depending on layout + collectionColumns: 0, //columns in horizontal layout, rows in vertical layout + collectionLayout: 'horizontal', //vertical + collectionMode: false, + collectionTileSize: 800, + collectionTileMargin: 80, + + //PERFORMANCE SETTINGS + imageLoaderLimit: 0, + maxImageCacheCount: 200, + timeout: 30000, + useCanvas: true, // Use canvas element for drawing if available + + //INTERFACE RESOURCE SETTINGS + prefixUrl: "/images/", + navImages: { + zoomIn: { + REST: 'zoomin_rest.png', + GROUP: 'zoomin_grouphover.png', + HOVER: 'zoomin_hover.png', + DOWN: 'zoomin_pressed.png' + }, + zoomOut: { + REST: 'zoomout_rest.png', + GROUP: 'zoomout_grouphover.png', + HOVER: 'zoomout_hover.png', + DOWN: 'zoomout_pressed.png' + }, + home: { + REST: 'home_rest.png', + GROUP: 'home_grouphover.png', + HOVER: 'home_hover.png', + DOWN: 'home_pressed.png' + }, + fullpage: { + REST: 'fullpage_rest.png', + GROUP: 'fullpage_grouphover.png', + HOVER: 'fullpage_hover.png', + DOWN: 'fullpage_pressed.png' + }, + rotateleft: { + REST: 'rotateleft_rest.png', + GROUP: 'rotateleft_grouphover.png', + HOVER: 'rotateleft_hover.png', + DOWN: 'rotateleft_pressed.png' + }, + rotateright: { + REST: 'rotateright_rest.png', + GROUP: 'rotateright_grouphover.png', + HOVER: 'rotateright_hover.png', + DOWN: 'rotateright_pressed.png' + }, + previous: { + REST: 'previous_rest.png', + GROUP: 'previous_grouphover.png', + HOVER: 'previous_hover.png', + DOWN: 'previous_pressed.png' + }, + next: { + REST: 'next_rest.png', + GROUP: 'next_grouphover.png', + HOVER: 'next_hover.png', + DOWN: 'next_pressed.png' + } + }, + + //DEVELOPER SETTINGS + debugMode: false, + debugGridColor: ['#437AB2', '#1B9E77', '#D95F02', '#7570B3', '#E7298A', '#66A61E', '#E6AB02', '#A6761D', '#666666'] + }, + + + /** + * TODO: get rid of this. I can't see how it's required at all. Looks + * like an early legacy code artifact. + * @static + * @ignore + */ + SIGNAL: "----seadragon----", + + + /** + * Returns a function which invokes the method as if it were a method belonging to the object. + * @function + * @param {Object} object + * @param {Function} method + * @returns {Function} + */ + delegate: function( object, method ) { + return function(){ + var args = arguments; + if ( args === undefined ){ + args = []; + } + return method.apply( object, args ); + }; + }, + + + /** + * An enumeration of Browser vendors. + * @static + * @type {Object} + * @property {Number} UNKNOWN + * @property {Number} IE + * @property {Number} FIREFOX + * @property {Number} SAFARI + * @property {Number} CHROME + * @property {Number} OPERA + */ + BROWSERS: { + UNKNOWN: 0, + IE: 1, + FIREFOX: 2, + SAFARI: 3, + CHROME: 4, + OPERA: 5 + }, + + + /** + * Returns a DOM Element for the given id or element. + * @function + * @param {String|Element} element Accepts an id or element. + * @returns {Element} The element with the given id, null, or the element itself. + */ + getElement: function( element ) { + if ( typeof ( element ) == "string" ) { + element = document.getElementById( element ); + } + return element; + }, + + + /** + * Determines the position of the upper-left corner of the element. + * @function + * @param {Element|String} element - the elemenet we want the position for. + * @returns {OpenSeadragon.Point} - the position of the upper left corner of the element. + */ + getElementPosition: function( element ) { + var result = new $.Point(), + isFixed, + offsetParent; + + element = $.getElement( element ); + isFixed = $.getElementStyle( element ).position == "fixed"; + offsetParent = getOffsetParent( element, isFixed ); + + while ( offsetParent ) { + + result.x += element.offsetLeft; + result.y += element.offsetTop; + + if ( isFixed ) { + result = result.plus( $.getPageScroll() ); + } + + element = offsetParent; + isFixed = $.getElementStyle( element ).position == "fixed"; + offsetParent = getOffsetParent( element, isFixed ); + } + + return result; + }, + + + /** + * Determines the position of the upper-left corner of the element adjusted for current page and/or element scroll. + * @function + * @param {Element|String} element - the element we want the position for. + * @returns {OpenSeadragon.Point} - the position of the upper left corner of the element adjusted for current page and/or element scroll. + */ + getElementOffset: function( element ) { + element = $.getElement( element ); + + var doc = element && element.ownerDocument, + docElement, + win, + boundingRect = { top: 0, left: 0 }; + + if ( !doc ) { + return new $.Point(); + } + + docElement = doc.documentElement; + + if ( typeof element.getBoundingClientRect !== typeof undefined ) { + boundingRect = element.getBoundingClientRect(); + } + + win = ( doc == doc.window ) ? + doc : + ( doc.nodeType === 9 ) ? + doc.defaultView || doc.parentWindow : + false; + + return new $.Point( + boundingRect.left + ( win.pageXOffset || docElement.scrollLeft ) - ( docElement.clientLeft || 0 ), + boundingRect.top + ( win.pageYOffset || docElement.scrollTop ) - ( docElement.clientTop || 0 ) + ); + }, + + + /** + * Determines the height and width of the given element. + * @function + * @param {Element|String} element + * @returns {OpenSeadragon.Point} + */ + getElementSize: function( element ) { + element = $.getElement( element ); + + return new $.Point( + element.clientWidth, + element.clientHeight + ); + }, + + + /** + * Returns the CSSStyle object for the given element. + * @function + * @param {Element|String} element + * @returns {CSSStyle} + */ + getElementStyle: + document.documentElement.currentStyle ? + function( element ) { + element = $.getElement( element ); + return element.currentStyle; + } : + function( element ) { + element = $.getElement( element ); + return window.getComputedStyle( element, "" ); + }, + + /** + * Returns the property with the correct vendor prefix appended. + * @param {String} property the property name + * @returns {String} the property with the correct prefix or null if not + * supported. + */ + getCssPropertyWithVendorPrefix: function(property) { + var memo = {}; + + $.getCssPropertyWithVendorPrefix = function(property) { + if (memo[property] !== undefined) { + return memo[property]; + } + var style = document.createElement('div').style; + var result = null; + if (style[property] !== undefined) { + result = property; + } else { + var prefixes = ['Webkit', 'Moz', 'MS', 'O', + 'webkit', 'moz', 'ms', 'o']; + var suffix = $.capitalizeFirstLetter(property); + for (var i = 0; i < prefixes.length; i++) { + var prop = prefixes[i] + suffix; + if (style[prop] !== undefined) { + result = prop; + break; + } + } + } + memo[property] = result; + return result; + }; + return $.getCssPropertyWithVendorPrefix(property); + }, + + /** + * Capitalizes the first letter of a string + * @param {String} string + * @returns {String} The string with the first letter capitalized + */ + capitalizeFirstLetter: function(string) { + return string.charAt(0).toUpperCase() + string.slice(1); + }, + + /** + * Compute the modulo of a number but makes sure to always return + * a positive value. + * @param {Number} number the number to computes the modulo of + * @param {Number} modulo the modulo + * @returns {Number} the result of the modulo of number + */ + positiveModulo: function(number, modulo) { + var result = number % modulo; + if (result < 0) { + result += modulo; + } + return result; + }, + + /** + * Determines if a point is within the bounding rectangle of the given element (hit-test). + * @function + * @param {Element|String} element + * @param {OpenSeadragon.Point} point + * @returns {Boolean} + */ + pointInElement: function( element, point ) { + element = $.getElement( element ); + var offset = $.getElementOffset( element ), + size = $.getElementSize( element ); + return point.x >= offset.x && point.x < offset.x + size.x && point.y < offset.y + size.y && point.y >= offset.y; + }, + + + /** + * Gets the latest event, really only useful internally since its + * specific to IE behavior. + * @function + * @param {Event} [event] + * @returns {Event} + * @deprecated For internal use only + * @private + */ + getEvent: function( event ) { + if( event ){ + $.getEvent = function( event ) { + return event; + }; + } else { + $.getEvent = function() { + return window.event; + }; + } + return $.getEvent( event ); + }, + + + /** + * Gets the position of the mouse on the screen for a given event. + * @function + * @param {Event} [event] + * @returns {OpenSeadragon.Point} + */ + getMousePosition: function( event ) { + + if ( typeof( event.pageX ) == "number" ) { + $.getMousePosition = function( event ){ + var result = new $.Point(); + + event = $.getEvent( event ); + result.x = event.pageX; + result.y = event.pageY; + + return result; + }; + } else if ( typeof( event.clientX ) == "number" ) { + $.getMousePosition = function( event ){ + var result = new $.Point(); + + event = $.getEvent( event ); + result.x = + event.clientX + + document.body.scrollLeft + + document.documentElement.scrollLeft; + result.y = + event.clientY + + document.body.scrollTop + + document.documentElement.scrollTop; + + return result; + }; + } else { + throw new Error( + "Unknown event mouse position, no known technique." + ); + } + + return $.getMousePosition( event ); + }, + + + /** + * Determines the page's current scroll position. + * @function + * @returns {OpenSeadragon.Point} + */ + getPageScroll: function() { + var docElement = document.documentElement || {}, + body = document.body || {}; + + if ( typeof( window.pageXOffset ) == "number" ) { + $.getPageScroll = function(){ + return new $.Point( + window.pageXOffset, + window.pageYOffset + ); + }; + } else if ( body.scrollLeft || body.scrollTop ) { + $.getPageScroll = function(){ + return new $.Point( + document.body.scrollLeft, + document.body.scrollTop + ); + }; + } else if ( docElement.scrollLeft || docElement.scrollTop ) { + $.getPageScroll = function(){ + return new $.Point( + document.documentElement.scrollLeft, + document.documentElement.scrollTop + ); + }; + } else { + // We can't reassign the function yet, as there was no scroll. + return new $.Point(0, 0); + } + + return $.getPageScroll(); + }, + + /** + * Set the page scroll position. + * @function + * @returns {OpenSeadragon.Point} + */ + setPageScroll: function( scroll ) { + if ( typeof ( window.scrollTo ) !== "undefined" ) { + $.setPageScroll = function( scroll ) { + window.scrollTo( scroll.x, scroll.y ); + }; + } else { + var originalScroll = $.getPageScroll(); + if ( originalScroll.x === scroll.x && + originalScroll.y === scroll.y ) { + // We are already correctly positioned and there + // is no way to detect the correct method. + return; + } + + document.body.scrollLeft = scroll.x; + document.body.scrollTop = scroll.y; + var currentScroll = $.getPageScroll(); + if ( currentScroll.x !== originalScroll.x && + currentScroll.y !== originalScroll.y ) { + $.setPageScroll = function( scroll ) { + document.body.scrollLeft = scroll.x; + document.body.scrollTop = scroll.y; + }; + return; + } + + document.documentElement.scrollLeft = scroll.x; + document.documentElement.scrollTop = scroll.y; + currentScroll = $.getPageScroll(); + if ( currentScroll.x !== originalScroll.x && + currentScroll.y !== originalScroll.y ) { + $.setPageScroll = function( scroll ) { + document.documentElement.scrollLeft = scroll.x; + document.documentElement.scrollTop = scroll.y; + }; + return; + } + + // We can't find anything working, so we do nothing. + $.setPageScroll = function( scroll ) { + }; + } + + return $.setPageScroll( scroll ); + }, + + /** + * Determines the size of the browsers window. + * @function + * @returns {OpenSeadragon.Point} + */ + getWindowSize: function() { + var docElement = document.documentElement || {}, + body = document.body || {}; + + if ( typeof( window.innerWidth ) == 'number' ) { + $.getWindowSize = function(){ + return new $.Point( + window.innerWidth, + window.innerHeight + ); + }; + } else if ( docElement.clientWidth || docElement.clientHeight ) { + $.getWindowSize = function(){ + return new $.Point( + document.documentElement.clientWidth, + document.documentElement.clientHeight + ); + }; + } else if ( body.clientWidth || body.clientHeight ) { + $.getWindowSize = function(){ + return new $.Point( + document.body.clientWidth, + document.body.clientHeight + ); + }; + } else { + throw new Error("Unknown window size, no known technique."); + } + + return $.getWindowSize(); + }, + + + /** + * Wraps the given element in a nest of divs so that the element can + * be easily centered using CSS tables + * @function + * @param {Element|String} element + * @returns {Element} outermost wrapper element + */ + makeCenteredNode: function( element ) { + // Convert a possible ID to an actual HTMLElement + element = $.getElement( element ); + + /* + CSS tables require you to have a display:table/row/cell hierarchy so we need to create + three nested wrapper divs: + */ + + var wrappers = [ + $.makeNeutralElement( 'div' ), + $.makeNeutralElement( 'div' ), + $.makeNeutralElement( 'div' ) + ]; + + // It feels like we should be able to pass style dicts to makeNeutralElement: + $.extend(wrappers[0].style, { + display: "table", + height: "100%", + width: "100%" + }); + + $.extend(wrappers[1].style, { + display: "table-row" + }); + + $.extend(wrappers[2].style, { + display: "table-cell", + verticalAlign: "middle", + textAlign: "center" + }); + + wrappers[0].appendChild(wrappers[1]); + wrappers[1].appendChild(wrappers[2]); + wrappers[2].appendChild(element); + + return wrappers[0]; + }, + + + /** + * Creates an easily positionable element of the given type that therefor + * serves as an excellent container element. + * @function + * @param {String} tagName + * @returns {Element} + */ + makeNeutralElement: function( tagName ) { + var element = document.createElement( tagName ), + style = element.style; + + style.background = "transparent none"; + style.border = "none"; + style.margin = "0px"; + style.padding = "0px"; + style.position = "static"; + + return element; + }, + + + /** + * Returns the current milliseconds, using Date.now() if available + * @function + */ + now: function( ) { + if (Date.now) { + $.now = Date.now; + } else { + $.now = function() { + return new Date().getTime(); + }; + } + + return $.now(); + }, + + + /** + * Ensures an image is loaded correctly to support alpha transparency. + * Generally only IE has issues doing this correctly for formats like + * png. + * @function + * @param {String} src + * @returns {Element} + */ + makeTransparentImage: function( src ) { + + $.makeTransparentImage = function( src ){ + var img = $.makeNeutralElement( "img" ); + + img.src = src; + + return img; + }; + + if ( $.Browser.vendor == $.BROWSERS.IE && $.Browser.version < 7 ) { + + $.makeTransparentImage = function( src ){ + var img = $.makeNeutralElement( "img" ), + element = null; + + element = $.makeNeutralElement("span"); + element.style.display = "inline-block"; + + img.onload = function() { + element.style.width = element.style.width || img.width + "px"; + element.style.height = element.style.height || img.height + "px"; + + img.onload = null; + img = null; // to prevent memory leaks in IE + }; + + img.src = src; + element.style.filter = + "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + + src + + "', sizingMethod='scale')"; + + return element; + }; + + } + + return $.makeTransparentImage( src ); + }, + + + /** + * Sets the opacity of the specified element. + * @function + * @param {Element|String} element + * @param {Number} opacity + * @param {Boolean} [usesAlpha] + */ + setElementOpacity: function( element, opacity, usesAlpha ) { + + var ieOpacity, + ieFilter; + + element = $.getElement( element ); + + if ( usesAlpha && !$.Browser.alpha ) { + opacity = Math.round( opacity ); + } + + if ( $.Browser.opacity ) { + element.style.opacity = opacity < 1 ? opacity : ""; + } else { + if ( opacity < 1 ) { + ieOpacity = Math.round( 100 * opacity ); + ieFilter = "alpha(opacity=" + ieOpacity + ")"; + element.style.filter = ieFilter; + } else { + element.style.filter = ""; + } + } + }, + + + /** + * Sets the specified element's touch-action style attribute to 'none'. + * @function + * @param {Element|String} element + */ + setElementTouchActionNone: function( element ) { + element = $.getElement( element ); + if ( typeof element.style.touchAction !== 'undefined' ) { + element.style.touchAction = 'none'; + } else if ( typeof element.style.msTouchAction !== 'undefined' ) { + element.style.msTouchAction = 'none'; + } + }, + + + /** + * Add the specified CSS class to the element if not present. + * @function + * @param {Element|String} element + * @param {String} className + */ + addClass: function( element, className ) { + element = $.getElement( element ); + + if (!element.className) { + element.className = className; + } else if ( ( ' ' + element.className + ' ' ). + indexOf( ' ' + className + ' ' ) === -1 ) { + element.className += ' ' + className; + } + }, + + /** + * Find the first index at which an element is found in an array or -1 + * if not present. + * + * Code taken and adapted from + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf#Compatibility + * + * @function + * @param {Array} array The array from which to find the element + * @param {Object} searchElement The element to find + * @param {Number} [fromIndex=0] Index to start research. + * @returns {Number} The index of the element in the array. + */ + indexOf: function( array, searchElement, fromIndex ) { + if ( Array.prototype.indexOf ) { + this.indexOf = function( array, searchElement, fromIndex ) { + return array.indexOf( searchElement, fromIndex ); + }; + } else { + this.indexOf = function( array, searchElement, fromIndex ) { + var i, + pivot = ( fromIndex ) ? fromIndex : 0, + length; + if ( !array ) { + throw new TypeError( ); + } + + length = array.length; + if ( length === 0 || pivot >= length ) { + return -1; + } + + if ( pivot < 0 ) { + pivot = length - Math.abs( pivot ); + } + + for ( i = pivot; i < length; i++ ) { + if ( array[i] === searchElement ) { + return i; + } + } + return -1; + }; + } + return this.indexOf( array, searchElement, fromIndex ); + }, + + /** + * Remove the specified CSS class from the element. + * @function + * @param {Element|String} element + * @param {String} className + */ + removeClass: function( element, className ) { + var oldClasses, + newClasses = [], + i; + + element = $.getElement( element ); + oldClasses = element.className.split( /\s+/ ); + for ( i = 0; i < oldClasses.length; i++ ) { + if ( oldClasses[ i ] && oldClasses[ i ] !== className ) { + newClasses.push( oldClasses[ i ] ); + } + } + element.className = newClasses.join(' '); + }, + + + /** + * Adds an event listener for the given element, eventName and handler. + * @function + * @param {Element|String} element + * @param {String} eventName + * @param {Function} handler + * @param {Boolean} [useCapture] + */ + addEvent: (function () { + if ( window.addEventListener ) { + return function ( element, eventName, handler, useCapture ) { + element = $.getElement( element ); + element.addEventListener( eventName, handler, useCapture ); + }; + } else if ( window.attachEvent ) { + return function ( element, eventName, handler, useCapture ) { + element = $.getElement( element ); + element.attachEvent( 'on' + eventName, handler ); + }; + } else { + throw new Error( "No known event model." ); + } + }()), + + + /** + * Remove a given event listener for the given element, event type and + * handler. + * @function + * @param {Element|String} element + * @param {String} eventName + * @param {Function} handler + * @param {Boolean} [useCapture] + */ + removeEvent: (function () { + if ( window.removeEventListener ) { + return function ( element, eventName, handler, useCapture ) { + element = $.getElement( element ); + element.removeEventListener( eventName, handler, useCapture ); + }; + } else if ( window.detachEvent ) { + return function( element, eventName, handler, useCapture ) { + element = $.getElement( element ); + element.detachEvent( 'on' + eventName, handler ); + }; + } else { + throw new Error( "No known event model." ); + } + }()), + + + /** + * Cancels the default browser behavior had the event propagated all + * the way up the DOM to the window object. + * @function + * @param {Event} [event] + */ + cancelEvent: function( event ) { + event = $.getEvent( event ); + + if ( event.preventDefault ) { + $.cancelEvent = function( event ){ + // W3C for preventing default + event.preventDefault(); + }; + } else { + $.cancelEvent = function( event ){ + event = $.getEvent( event ); + // legacy for preventing default + event.cancel = true; + // IE for preventing default + event.returnValue = false; + }; + } + $.cancelEvent( event ); + }, + + + /** + * Stops the propagation of the event up the DOM. + * @function + * @param {Event} [event] + */ + stopEvent: function( event ) { + event = $.getEvent( event ); + + if ( event.stopPropagation ) { + // W3C for stopping propagation + $.stopEvent = function( event ){ + event.stopPropagation(); + }; + } else { + // IE for stopping propagation + $.stopEvent = function( event ){ + event = $.getEvent( event ); + event.cancelBubble = true; + }; + + } + + $.stopEvent( event ); + }, + + + /** + * Similar to OpenSeadragon.delegate, but it does not immediately call + * the method on the object, returning a function which can be called + * repeatedly to delegate the method. It also allows additonal arguments + * to be passed during construction which will be added during each + * invocation, and each invocation can add additional arguments as well. + * + * @function + * @param {Object} object + * @param {Function} method + * @param [args] any additional arguments are passed as arguments to the + * created callback + * @returns {Function} + */ + createCallback: function( object, method ) { + //TODO: This pattern is painful to use and debug. It's much cleaner + // to use pinning plus anonymous functions. Get rid of this + // pattern! + var initialArgs = [], + i; + for ( i = 2; i < arguments.length; i++ ) { + initialArgs.push( arguments[ i ] ); + } + + return function() { + var args = initialArgs.concat( [] ), + i; + for ( i = 0; i < arguments.length; i++ ) { + args.push( arguments[ i ] ); + } + + return method.apply( object, args ); + }; + }, + + + /** + * Retreives the value of a url parameter from the window.location string. + * @function + * @param {String} key + * @returns {String} The value of the url parameter or null if no param matches. + */ + getUrlParameter: function( key ) { + // eslint-disable-next-line no-use-before-define + var value = URLPARAMS[ key ]; + return value ? value : null; + }, + + /** + * Retrieves the protocol used by the url. The url can either be absolute + * or relative. + * @function + * @private + * @param {String} url The url to retrieve the protocol from. + * @return {String} The protocol (http:, https:, file:, ftp: ...) + */ + getUrlProtocol: function( url ) { + var match = url.match(/^([a-z]+:)\/\//i); + if ( match === null ) { + // Relative URL, retrive the protocol from window.location + return window.location.protocol; + } + return match[1].toLowerCase(); + }, + + /** + * Create an XHR object + * @private + * @param {type} [local] If set to true, the XHR will be file: protocol + * compatible if possible (but may raise a warning in the browser). + * @returns {XMLHttpRequest} + */ + createAjaxRequest: function( local ) { + // IE11 does not support window.ActiveXObject so we just try to + // create one to see if it is supported. + // See: http://msdn.microsoft.com/en-us/library/ie/dn423948%28v=vs.85%29.aspx + var supportActiveX; + try { + /* global ActiveXObject:true */ + supportActiveX = !!new ActiveXObject( "Microsoft.XMLHTTP" ); + } catch( e ) { + supportActiveX = false; + } + + if ( supportActiveX ) { + if ( window.XMLHttpRequest ) { + $.createAjaxRequest = function( local ) { + if ( local ) { + return new ActiveXObject( "Microsoft.XMLHTTP" ); + } + return new XMLHttpRequest(); + }; + } else { + $.createAjaxRequest = function() { + return new ActiveXObject( "Microsoft.XMLHTTP" ); + }; + } + } else if ( window.XMLHttpRequest ) { + $.createAjaxRequest = function() { + return new XMLHttpRequest(); + }; + } else { + throw new Error( "Browser doesn't support XMLHttpRequest." ); + } + return $.createAjaxRequest( local ); + }, + + /** + * Makes an AJAX request. + * @param {Object} options + * @param {String} options.url - the url to request + * @param {Function} options.success - a function to call on a successful response + * @param {Function} options.error - a function to call on when an error occurs + * @param {Object} options.headers - headers to add to the AJAX request + * @param {String} options.responseType - the response type of the the AJAX request + * @param {Boolean} [options.withCredentials=false] - whether to set the XHR's withCredentials + * @throws {Error} + * @returns {XMLHttpRequest} + */ + makeAjaxRequest: function( url, onSuccess, onError ) { + var withCredentials; + var headers; + var responseType; + + // Note that our preferred API is that you pass in a single object; the named + // arguments are for legacy support. + if( $.isPlainObject( url ) ){ + onSuccess = url.success; + onError = url.error; + withCredentials = url.withCredentials; + headers = url.headers; + responseType = url.responseType || null; + url = url.url; + } + + var protocol = $.getUrlProtocol( url ); + var request = $.createAjaxRequest( protocol === "file:" ); + + if ( !$.isFunction( onSuccess ) ) { + throw new Error( "makeAjaxRequest requires a success callback" ); + } + + request.onreadystatechange = function() { + // 4 = DONE (https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#Properties) + if ( request.readyState == 4 ) { + request.onreadystatechange = function(){}; + + // With protocols other than http/https, a successful request status is in + // the 200's on Firefox and 0 on other browsers + if ( (request.status >= 200 && request.status < 300) || + ( request.status === 0 && + protocol !== "http:" && + protocol !== "https:" )) { + onSuccess( request ); + } else { + $.console.log( "AJAX request returned %d: %s", request.status, url ); + + if ( $.isFunction( onError ) ) { + onError( request ); + } + } + } + }; + + try { + request.open( "GET", url, true ); + + if (responseType) { + request.responseType = responseType; + } + + if (headers) { + for (var headerName in headers) { + if (headers.hasOwnProperty(headerName) && headers[headerName]) { + request.setRequestHeader(headerName, headers[headerName]); + } + } + } + + if (withCredentials) { + request.withCredentials = true; + } + + request.send(null); + } catch (e) { + var msg = e.message; + + /* + IE < 10 does not support CORS and an XHR request to a different origin will fail as soon + as send() is called. This is particularly easy to miss during development and appear in + production if you use a CDN or domain sharding and the security policy is likely to break + exception handlers since any attempt to access a property of the request object will + raise an access denied TypeError inside the catch block. + + To be friendlier, we'll check for this specific error and add a documentation pointer + to point developers in the right direction. We test the exception number because IE's + error messages are localized. + */ + var oldIE = $.Browser.vendor == $.BROWSERS.IE && $.Browser.version < 10; + if ( oldIE && typeof( e.number ) != "undefined" && e.number == -2147024891 ) { + msg += "\nSee http://msdn.microsoft.com/en-us/library/ms537505(v=vs.85).aspx#xdomain"; + } + + $.console.log( "%s while making AJAX request: %s", e.name, msg ); + + request.onreadystatechange = function(){}; + + if (window.XDomainRequest) { // IE9 or IE8 might as well try to use XDomainRequest + var xdr = new XDomainRequest(); + if (xdr) { + xdr.onload = function (e) { + if ( $.isFunction( onSuccess ) ) { + onSuccess({ // Faking an xhr object + responseText: xdr.responseText, + status: 200, // XDomainRequest doesn't support status codes, so we just fake one! :/ + statusText: 'OK' + }); + } + }; + xdr.onerror = function (e) { + if ($.isFunction(onError)) { + onError({ // Faking an xhr object + responseText: xdr.responseText, + status: 444, // 444 No Response + statusText: 'An error happened. Due to an XDomainRequest deficiency we can not extract any information about this error. Upgrade your browser.' + }); + } + }; + try { + xdr.open('GET', url); + xdr.send(); + } catch (e2) { + if ( $.isFunction( onError ) ) { + onError( request, e ); + } + } + } + } else { + if ( $.isFunction( onError ) ) { + onError( request, e ); + } + } + } + + return request; + }, + + /** + * Taken from jQuery 1.6.1 + * @function + * @param {Object} options + * @param {String} options.url + * @param {Function} options.callback + * @param {String} [options.param='callback'] The name of the url parameter + * to request the jsonp provider with. + * @param {String} [options.callbackName=] The name of the callback to + * request the jsonp provider with. + */ + jsonp: function( options ){ + var script, + url = options.url, + head = document.head || + document.getElementsByTagName( "head" )[ 0 ] || + document.documentElement, + jsonpCallback = options.callbackName || 'openseadragon' + $.now(), + previous = window[ jsonpCallback ], + replace = "$1" + jsonpCallback + "$2", + callbackParam = options.param || 'callback', + callback = options.callback; + + url = url.replace( /(\=)\?(&|$)|\?\?/i, replace ); + // Add callback manually + url += (/\?/.test( url ) ? "&" : "?") + callbackParam + "=" + jsonpCallback; + + // Install callback + window[ jsonpCallback ] = function( response ) { + if ( !previous ){ + try{ + delete window[ jsonpCallback ]; + }catch(e){ + //swallow + } + } else { + window[ jsonpCallback ] = previous; + } + if( callback && $.isFunction( callback ) ){ + callback( response ); + } + }; + + script = document.createElement( "script" ); + + //TODO: having an issue with async info requests + if( undefined !== options.async || false !== options.async ){ + script.async = "async"; + } + + if ( options.scriptCharset ) { + script.charset = options.scriptCharset; + } + + script.src = url; + + // Attach handlers for all browsers + script.onload = script.onreadystatechange = function( _, isAbort ) { + + if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { + + // Handle memory leak in IE + script.onload = script.onreadystatechange = null; + + // Remove the script + if ( head && script.parentNode ) { + head.removeChild( script ); + } + + // Dereference the script + script = undefined; + } + }; + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709 and #4378). + head.insertBefore( script, head.firstChild ); + + }, + + + /** + * Fully deprecated. Will throw an error. + * @function + * @deprecated use {@link OpenSeadragon.Viewer#open} + */ + createFromDZI: function() { + throw "OpenSeadragon.createFromDZI is deprecated, use Viewer.open."; + }, + + /** + * Parses an XML string into a DOM Document. + * @function + * @param {String} string + * @returns {Document} + */ + parseXml: function( string ) { + if ( window.DOMParser ) { + + $.parseXml = function( string ) { + var xmlDoc = null, + parser; + + parser = new DOMParser(); + xmlDoc = parser.parseFromString( string, "text/xml" ); + return xmlDoc; + }; + + } else if ( window.ActiveXObject ) { + + $.parseXml = function( string ) { + var xmlDoc = null; + + xmlDoc = new ActiveXObject( "Microsoft.XMLDOM" ); + xmlDoc.async = false; + xmlDoc.loadXML( string ); + return xmlDoc; + }; + + } else { + throw new Error( "Browser doesn't support XML DOM." ); + } + + return $.parseXml( string ); + }, + + /** + * Parses a JSON string into a Javascript object. + * @function + * @param {String} string + * @returns {Object} + */ + parseJSON: function(string) { + if (window.JSON && window.JSON.parse) { + $.parseJSON = window.JSON.parse; + } else { + // Should only be used by IE8 in non standards mode + $.parseJSON = function(string) { + /*jshint evil:true*/ + //eslint-disable-next-line no-eval + return eval('(' + string + ')'); + }; + } + return $.parseJSON(string); + }, + + /** + * Reports whether the image format is supported for tiling in this + * version. + * @function + * @param {String} [extension] + * @returns {Boolean} + */ + imageFormatSupported: function( extension ) { + extension = extension ? extension : ""; + // eslint-disable-next-line no-use-before-define + return !!FILEFORMATS[ extension.toLowerCase() ]; + } + + }); + + + /** + * The current browser vendor, version, and related information regarding detected features. + * @member {Object} Browser + * @memberof OpenSeadragon + * @static + * @type {Object} + * @property {OpenSeadragon.BROWSERS} vendor - One of the {@link OpenSeadragon.BROWSERS} enumeration values. + * @property {Number} version + * @property {Boolean} alpha - Does the browser support image alpha transparency. + */ + $.Browser = { + vendor: $.BROWSERS.UNKNOWN, + version: 0, + alpha: true + }; + + + var FILEFORMATS = { + "bmp": false, + "jpeg": true, + "jpg": true, + "png": true, + "tif": false, + "wdp": false + }, + URLPARAMS = {}; + + (function() { + //A small auto-executing routine to determine the browser vendor, + //version and supporting feature sets. + var ver = navigator.appVersion, + ua = navigator.userAgent, + regex; + + //console.error( 'appName: ' + navigator.appName ); + //console.error( 'appVersion: ' + navigator.appVersion ); + //console.error( 'userAgent: ' + navigator.userAgent ); + + switch( navigator.appName ){ + case "Microsoft Internet Explorer": + if( !!window.attachEvent && + !!window.ActiveXObject ) { + + $.Browser.vendor = $.BROWSERS.IE; + $.Browser.version = parseFloat( + ua.substring( + ua.indexOf( "MSIE" ) + 5, + ua.indexOf( ";", ua.indexOf( "MSIE" ) ) ) + ); + } + break; + case "Netscape": + if (window.addEventListener) { + if ( ua.indexOf( "Firefox" ) >= 0 ) { + $.Browser.vendor = $.BROWSERS.FIREFOX; + $.Browser.version = parseFloat( + ua.substring( ua.indexOf( "Firefox" ) + 8 ) + ); + } else if ( ua.indexOf( "Safari" ) >= 0 ) { + $.Browser.vendor = ua.indexOf( "Chrome" ) >= 0 ? + $.BROWSERS.CHROME : + $.BROWSERS.SAFARI; + $.Browser.version = parseFloat( + ua.substring( + ua.substring( 0, ua.indexOf( "Safari" ) ).lastIndexOf( "/" ) + 1, + ua.indexOf( "Safari" ) + ) + ); + } else { + regex = new RegExp( "Trident/.*rv:([0-9]{1,}[.0-9]{0,})"); + if ( regex.exec( ua ) !== null ) { + $.Browser.vendor = $.BROWSERS.IE; + $.Browser.version = parseFloat( RegExp.$1 ); + } + } + } + break; + case "Opera": + $.Browser.vendor = $.BROWSERS.OPERA; + $.Browser.version = parseFloat( ver ); + break; + } + + // ignore '?' portion of query string + var query = window.location.search.substring( 1 ), + parts = query.split('&'), + part, + sep, + i; + + for ( i = 0; i < parts.length; i++ ) { + part = parts[ i ]; + sep = part.indexOf( '=' ); + + if ( sep > 0 ) { + URLPARAMS[ part.substring( 0, sep ) ] = + decodeURIComponent( part.substring( sep + 1 ) ); + } + } + + //determine if this browser supports image alpha transparency + $.Browser.alpha = !( + ( + $.Browser.vendor == $.BROWSERS.IE && + $.Browser.version < 9 + ) || ( + $.Browser.vendor == $.BROWSERS.CHROME && + $.Browser.version < 2 + ) + ); + + //determine if this browser supports element.style.opacity + $.Browser.opacity = !( + $.Browser.vendor == $.BROWSERS.IE && + $.Browser.version < 9 + ); + + })(); + + + //TODO: $.console is often used inside a try/catch block which generally + // prevents allowings errors to occur with detection until a debugger + // is attached. Although I've been guilty of the same anti-pattern + // I eventually was convinced that errors should naturally propogate in + // all but the most special cases. + /** + * A convenient alias for console when available, and a simple null + * function when console is unavailable. + * @static + * @private + */ + var nullfunction = function( msg ){ + //document.location.hash = msg; + }; + + $.console = window.console || { + log: nullfunction, + debug: nullfunction, + info: nullfunction, + warn: nullfunction, + error: nullfunction, + assert: nullfunction + }; + + + // Adding support for HTML5's requestAnimationFrame as suggested by acdha. + // Implementation taken from matt synder's post here: + // http://mattsnider.com/cross-browser-and-legacy-supported-requestframeanimation/ + (function( w ) { + + // most browsers have an implementation + var requestAnimationFrame = w.requestAnimationFrame || + w.mozRequestAnimationFrame || + w.webkitRequestAnimationFrame || + w.msRequestAnimationFrame; + + var cancelAnimationFrame = w.cancelAnimationFrame || + w.mozCancelAnimationFrame || + w.webkitCancelAnimationFrame || + w.msCancelAnimationFrame; + + // polyfill, when necessary + if ( requestAnimationFrame && cancelAnimationFrame ) { + // We can't assign these window methods directly to $ because they + // expect their "this" to be "window", so we call them in wrappers. + $.requestAnimationFrame = function(){ + return requestAnimationFrame.apply( w, arguments ); + }; + $.cancelAnimationFrame = function(){ + return cancelAnimationFrame.apply( w, arguments ); + }; + } else { + var aAnimQueue = [], + processing = [], + iRequestId = 0, + iIntervalId; + + // create a mock requestAnimationFrame function + $.requestAnimationFrame = function( callback ) { + aAnimQueue.push( [ ++iRequestId, callback ] ); + + if ( !iIntervalId ) { + iIntervalId = setInterval( function() { + if ( aAnimQueue.length ) { + var time = $.now(); + // Process all of the currently outstanding frame + // requests, but none that get added during the + // processing. + // Swap the arrays so we don't have to create a new + // array every frame. + var temp = processing; + processing = aAnimQueue; + aAnimQueue = temp; + while ( processing.length ) { + processing.shift()[ 1 ]( time ); + } + } else { + // don't continue the interval, if unnecessary + clearInterval( iIntervalId ); + iIntervalId = undefined; + } + }, 1000 / 50); // estimating support for 50 frames per second + } + + return iRequestId; + }; + + // create a mock cancelAnimationFrame function + $.cancelAnimationFrame = function( requestId ) { + // find the request ID and remove it + var i, j; + for ( i = 0, j = aAnimQueue.length; i < j; i += 1 ) { + if ( aAnimQueue[ i ][ 0 ] === requestId ) { + aAnimQueue.splice( i, 1 ); + return; + } + } + + // If it's not in the queue, it may be in the set we're currently + // processing (if cancelAnimationFrame is called from within a + // requestAnimationFrame callback). + for ( i = 0, j = processing.length; i < j; i += 1 ) { + if ( processing[ i ][ 0 ] === requestId ) { + processing.splice( i, 1 ); + return; + } + } + }; + } + })( window ); + + /** + * @private + * @inner + * @function + * @param {Element} element + * @param {Boolean} [isFixed] + * @returns {Element} + */ + function getOffsetParent( element, isFixed ) { + if ( isFixed && element != document.body ) { + return document.body; + } else { + return element.offsetParent; + } + } + +}(OpenSeadragon)); + + +// Universal Module Definition, supports CommonJS, AMD and simple script tag +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // expose as amd module + define([], factory); + } else if (typeof module === 'object' && module.exports) { + // expose as commonjs module + module.exports = factory(); + } else { + // expose as window.OpenSeadragon + root.OpenSeadragon = factory(); + } +}(this, function () { + return OpenSeadragon; +})); + +/* + * OpenSeadragon - full-screen support functions + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ) { + /** + * Determine native full screen support we can get from the browser. + * @member fullScreenApi + * @memberof OpenSeadragon + * @type {object} + * @property {Boolean} supportsFullScreen Return true if full screen API is supported. + * @property {Function} isFullScreen Return true if currently in full screen mode. + * @property {Function} getFullScreenElement Return the element currently in full screen mode. + * @property {Function} requestFullScreen Make a request to go in full screen mode. + * @property {Function} exitFullScreen Make a request to exit full screen mode. + * @property {Function} cancelFullScreen Deprecated, use exitFullScreen instead. + * @property {String} fullScreenEventName Event fired when the full screen mode change. + * @property {String} fullScreenErrorEventName Event fired when a request to go + * in full screen mode failed. + */ + var fullScreenApi = { + supportsFullScreen: false, + isFullScreen: function() { return false; }, + getFullScreenElement: function() { return null; }, + requestFullScreen: function() {}, + exitFullScreen: function() {}, + cancelFullScreen: function() {}, + fullScreenEventName: '', + fullScreenErrorEventName: '' + }; + + // check for native support + if ( document.exitFullscreen ) { + // W3C standard + fullScreenApi.supportsFullScreen = true; + fullScreenApi.getFullScreenElement = function() { + return document.fullscreenElement; + }; + fullScreenApi.requestFullScreen = function( element ) { + return element.requestFullscreen(); + }; + fullScreenApi.exitFullScreen = function() { + document.exitFullscreen(); + }; + fullScreenApi.fullScreenEventName = "fullscreenchange"; + fullScreenApi.fullScreenErrorEventName = "fullscreenerror"; + } else if ( document.msExitFullscreen ) { + // IE 11 + fullScreenApi.supportsFullScreen = true; + fullScreenApi.getFullScreenElement = function() { + return document.msFullscreenElement; + }; + fullScreenApi.requestFullScreen = function( element ) { + return element.msRequestFullscreen(); + }; + fullScreenApi.exitFullScreen = function() { + document.msExitFullscreen(); + }; + fullScreenApi.fullScreenEventName = "MSFullscreenChange"; + fullScreenApi.fullScreenErrorEventName = "MSFullscreenError"; + } else if ( document.webkitExitFullscreen ) { + // Recent webkit + fullScreenApi.supportsFullScreen = true; + fullScreenApi.getFullScreenElement = function() { + return document.webkitFullscreenElement; + }; + fullScreenApi.requestFullScreen = function( element ) { + return element.webkitRequestFullscreen(); + }; + fullScreenApi.exitFullScreen = function() { + document.webkitExitFullscreen(); + }; + fullScreenApi.fullScreenEventName = "webkitfullscreenchange"; + fullScreenApi.fullScreenErrorEventName = "webkitfullscreenerror"; + } else if ( document.webkitCancelFullScreen ) { + // Old webkit + fullScreenApi.supportsFullScreen = true; + fullScreenApi.getFullScreenElement = function() { + return document.webkitCurrentFullScreenElement; + }; + fullScreenApi.requestFullScreen = function( element ) { + return element.webkitRequestFullScreen(); + }; + fullScreenApi.exitFullScreen = function() { + document.webkitCancelFullScreen(); + }; + fullScreenApi.fullScreenEventName = "webkitfullscreenchange"; + fullScreenApi.fullScreenErrorEventName = "webkitfullscreenerror"; + } else if ( document.mozCancelFullScreen ) { + // Firefox + fullScreenApi.supportsFullScreen = true; + fullScreenApi.getFullScreenElement = function() { + return document.mozFullScreenElement; + }; + fullScreenApi.requestFullScreen = function( element ) { + return element.mozRequestFullScreen(); + }; + fullScreenApi.exitFullScreen = function() { + document.mozCancelFullScreen(); + }; + fullScreenApi.fullScreenEventName = "mozfullscreenchange"; + fullScreenApi.fullScreenErrorEventName = "mozfullscreenerror"; + } + fullScreenApi.isFullScreen = function() { + return fullScreenApi.getFullScreenElement() !== null; + }; + fullScreenApi.cancelFullScreen = function() { + $.console.error("cancelFullScreen is deprecated. Use exitFullScreen instead."); + fullScreenApi.exitFullScreen(); + }; + + // export api + $.extend( $, fullScreenApi ); + +})( OpenSeadragon ); + +/* + * OpenSeadragon - EventSource + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function($){ + +/** + * Event handler method signature used by all OpenSeadragon events. + * + * @callback EventHandler + * @memberof OpenSeadragon + * @param {Object} event - See individual events for event-specific properties. + */ + + +/** + * @class EventSource + * @classdesc For use by classes which want to support custom, non-browser events. + * + * @memberof OpenSeadragon + */ +$.EventSource = function() { + this.events = {}; +}; + +/** @lends OpenSeadragon.EventSource.prototype */ +$.EventSource.prototype = { + + /** + * Add an event handler to be triggered only once (or a given number of times) + * for a given event. + * @function + * @param {String} eventName - Name of event to register. + * @param {OpenSeadragon.EventHandler} handler - Function to call when event + * is triggered. + * @param {Object} [userData=null] - Arbitrary object to be passed unchanged + * to the handler. + * @param {Number} [times=1] - The number of times to handle the event + * before removing it. + */ + addOnceHandler: function(eventName, handler, userData, times) { + var self = this; + times = times || 1; + var count = 0; + var onceHandler = function(event) { + count++; + if (count === times) { + self.removeHandler(eventName, onceHandler); + } + handler(event); + }; + this.addHandler(eventName, onceHandler, userData); + }, + + /** + * Add an event handler for a given event. + * @function + * @param {String} eventName - Name of event to register. + * @param {OpenSeadragon.EventHandler} handler - Function to call when event is triggered. + * @param {Object} [userData=null] - Arbitrary object to be passed unchanged to the handler. + */ + addHandler: function ( eventName, handler, userData ) { + var events = this.events[ eventName ]; + if ( !events ) { + this.events[ eventName ] = events = []; + } + if ( handler && $.isFunction( handler ) ) { + events[ events.length ] = { handler: handler, userData: userData || null }; + } + }, + + /** + * Remove a specific event handler for a given event. + * @function + * @param {String} eventName - Name of event for which the handler is to be removed. + * @param {OpenSeadragon.EventHandler} handler - Function to be removed. + */ + removeHandler: function ( eventName, handler ) { + var events = this.events[ eventName ], + handlers = [], + i; + if ( !events ) { + return; + } + if ( $.isArray( events ) ) { + for ( i = 0; i < events.length; i++ ) { + if ( events[i].handler !== handler ) { + handlers.push( events[ i ] ); + } + } + this.events[ eventName ] = handlers; + } + }, + + + /** + * Remove all event handlers for a given event type. If no type is given all + * event handlers for every event type are removed. + * @function + * @param {String} eventName - Name of event for which all handlers are to be removed. + */ + removeAllHandlers: function( eventName ) { + if ( eventName ){ + this.events[ eventName ] = []; + } else{ + for ( var eventType in this.events ) { + this.events[ eventType ] = []; + } + } + }, + + /** + * Get a function which iterates the list of all handlers registered for a given event, calling the handler for each. + * @function + * @param {String} eventName - Name of event to get handlers for. + */ + getHandler: function ( eventName ) { + var events = this.events[ eventName ]; + if ( !events || !events.length ) { + return null; + } + events = events.length === 1 ? + [ events[ 0 ] ] : + Array.apply( null, events ); + return function ( source, args ) { + var i, + length = events.length; + for ( i = 0; i < length; i++ ) { + if ( events[ i ] ) { + args.eventSource = source; + args.userData = events[ i ].userData; + events[ i ].handler( args ); + } + } + }; + }, + + /** + * Trigger an event, optionally passing additional information. + * @function + * @param {String} eventName - Name of event to register. + * @param {Object} eventArgs - Event-specific data. + */ + raiseEvent: function( eventName, eventArgs ) { + //uncomment if you want to get a log of all events + //$.console.log( eventName ); + var handler = this.getHandler( eventName ); + + if ( handler ) { + if ( !eventArgs ) { + eventArgs = {}; + } + + handler( this, eventArgs ); + } + } +}; + +}( OpenSeadragon )); + +/* + * OpenSeadragon - MouseTracker + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function ( $ ) { + + // All MouseTracker instances + var MOUSETRACKERS = []; + + // dictionary from hash to private properties + var THIS = {}; + + + /** + * @class MouseTracker + * @classdesc Provides simplified handling of common pointer device (mouse, touch, pen, etc.) gestures + * and keyboard events on a specified element. + * @memberof OpenSeadragon + * @param {Object} options + * Allows configurable properties to be entirely specified by passing + * an options object to the constructor. The constructor also supports + * the original positional arguments 'element', 'clickTimeThreshold', + * and 'clickDistThreshold' in that order. + * @param {Element|String} options.element + * A reference to an element or an element id for which the pointer/key + * events will be monitored. + * @param {Boolean} [options.startDisabled=false] + * If true, event tracking on the element will not start until + * {@link OpenSeadragon.MouseTracker.setTracking|setTracking} is called. + * @param {Number} options.clickTimeThreshold + * The number of milliseconds within which a pointer down-up event combination + * will be treated as a click gesture. + * @param {Number} options.clickDistThreshold + * The maximum distance allowed between a pointer down event and a pointer up event + * to be treated as a click gesture. + * @param {Number} options.dblClickTimeThreshold + * The number of milliseconds within which two pointer down-up event combinations + * will be treated as a double-click gesture. + * @param {Number} options.dblClickDistThreshold + * The maximum distance allowed between two pointer click events + * to be treated as a click gesture. + * @param {Number} [options.stopDelay=50] + * The number of milliseconds without pointer move before the stop + * event is fired. + * @param {OpenSeadragon.EventHandler} [options.enterHandler=null] + * An optional handler for pointer enter. + * @param {OpenSeadragon.EventHandler} [options.exitHandler=null] + * An optional handler for pointer exit. + * @param {OpenSeadragon.EventHandler} [options.pressHandler=null] + * An optional handler for pointer press. + * @param {OpenSeadragon.EventHandler} [options.nonPrimaryPressHandler=null] + * An optional handler for pointer non-primary button press. + * @param {OpenSeadragon.EventHandler} [options.releaseHandler=null] + * An optional handler for pointer release. + * @param {OpenSeadragon.EventHandler} [options.nonPrimaryReleaseHandler=null] + * An optional handler for pointer non-primary button release. + * @param {OpenSeadragon.EventHandler} [options.moveHandler=null] + * An optional handler for pointer move. + * @param {OpenSeadragon.EventHandler} [options.scrollHandler=null] + * An optional handler for mouse wheel scroll. + * @param {OpenSeadragon.EventHandler} [options.clickHandler=null] + * An optional handler for pointer click. + * @param {OpenSeadragon.EventHandler} [options.dblClickHandler=null] + * An optional handler for pointer double-click. + * @param {OpenSeadragon.EventHandler} [options.dragHandler=null] + * An optional handler for the drag gesture. + * @param {OpenSeadragon.EventHandler} [options.dragEndHandler=null] + * An optional handler for after a drag gesture. + * @param {OpenSeadragon.EventHandler} [options.pinchHandler=null] + * An optional handler for the pinch gesture. + * @param {OpenSeadragon.EventHandler} [options.keyDownHandler=null] + * An optional handler for keydown. + * @param {OpenSeadragon.EventHandler} [options.keyUpHandler=null] + * An optional handler for keyup. + * @param {OpenSeadragon.EventHandler} [options.keyHandler=null] + * An optional handler for keypress. + * @param {OpenSeadragon.EventHandler} [options.focusHandler=null] + * An optional handler for focus. + * @param {OpenSeadragon.EventHandler} [options.blurHandler=null] + * An optional handler for blur. + * @param {Object} [options.userData=null] + * Arbitrary object to be passed unchanged to any attached handler methods. + */ + $.MouseTracker = function ( options ) { + + MOUSETRACKERS.push( this ); + + var args = arguments; + + if ( !$.isPlainObject( options ) ) { + options = { + element: args[ 0 ], + clickTimeThreshold: args[ 1 ], + clickDistThreshold: args[ 2 ] + }; + } + + this.hash = Math.random(); // An unique hash for this tracker. + /** + * The element for which pointer events are being monitored. + * @member {Element} element + * @memberof OpenSeadragon.MouseTracker# + */ + this.element = $.getElement( options.element ); + /** + * The number of milliseconds within which a pointer down-up event combination + * will be treated as a click gesture. + * @member {Number} clickTimeThreshold + * @memberof OpenSeadragon.MouseTracker# + */ + this.clickTimeThreshold = options.clickTimeThreshold || $.DEFAULT_SETTINGS.clickTimeThreshold; + /** + * The maximum distance allowed between a pointer down event and a pointer up event + * to be treated as a click gesture. + * @member {Number} clickDistThreshold + * @memberof OpenSeadragon.MouseTracker# + */ + this.clickDistThreshold = options.clickDistThreshold || $.DEFAULT_SETTINGS.clickDistThreshold; + /** + * The number of milliseconds within which two pointer down-up event combinations + * will be treated as a double-click gesture. + * @member {Number} dblClickTimeThreshold + * @memberof OpenSeadragon.MouseTracker# + */ + this.dblClickTimeThreshold = options.dblClickTimeThreshold || $.DEFAULT_SETTINGS.dblClickTimeThreshold; + /** + * The maximum distance allowed between two pointer click events + * to be treated as a click gesture. + * @member {Number} clickDistThreshold + * @memberof OpenSeadragon.MouseTracker# + */ + this.dblClickDistThreshold = options.dblClickDistThreshold || $.DEFAULT_SETTINGS.dblClickDistThreshold; + /*eslint-disable no-multi-spaces*/ + this.userData = options.userData || null; + this.stopDelay = options.stopDelay || 50; + + this.enterHandler = options.enterHandler || null; + this.exitHandler = options.exitHandler || null; + this.pressHandler = options.pressHandler || null; + this.nonPrimaryPressHandler = options.nonPrimaryPressHandler || null; + this.releaseHandler = options.releaseHandler || null; + this.nonPrimaryReleaseHandler = options.nonPrimaryReleaseHandler || null; + this.moveHandler = options.moveHandler || null; + this.scrollHandler = options.scrollHandler || null; + this.clickHandler = options.clickHandler || null; + this.dblClickHandler = options.dblClickHandler || null; + this.dragHandler = options.dragHandler || null; + this.dragEndHandler = options.dragEndHandler || null; + this.pinchHandler = options.pinchHandler || null; + this.stopHandler = options.stopHandler || null; + this.keyDownHandler = options.keyDownHandler || null; + this.keyUpHandler = options.keyUpHandler || null; + this.keyHandler = options.keyHandler || null; + this.focusHandler = options.focusHandler || null; + this.blurHandler = options.blurHandler || null; + /*eslint-enable no-multi-spaces*/ + + //Store private properties in a scope sealed hash map + var _this = this; + + /** + * @private + * @property {Boolean} tracking + * Are we currently tracking pointer events for this element. + */ + THIS[ this.hash ] = { + click: function ( event ) { onClick( _this, event ); }, + dblclick: function ( event ) { onDblClick( _this, event ); }, + keydown: function ( event ) { onKeyDown( _this, event ); }, + keyup: function ( event ) { onKeyUp( _this, event ); }, + keypress: function ( event ) { onKeyPress( _this, event ); }, + focus: function ( event ) { onFocus( _this, event ); }, + blur: function ( event ) { onBlur( _this, event ); }, + + wheel: function ( event ) { onWheel( _this, event ); }, + mousewheel: function ( event ) { onMouseWheel( _this, event ); }, + DOMMouseScroll: function ( event ) { onMouseWheel( _this, event ); }, + MozMousePixelScroll: function ( event ) { onMouseWheel( _this, event ); }, + + mouseenter: function ( event ) { onMouseEnter( _this, event ); }, // Used on IE8 only + mouseleave: function ( event ) { onMouseLeave( _this, event ); }, // Used on IE8 only + mouseover: function ( event ) { onMouseOver( _this, event ); }, + mouseout: function ( event ) { onMouseOut( _this, event ); }, + mousedown: function ( event ) { onMouseDown( _this, event ); }, + mouseup: function ( event ) { onMouseUp( _this, event ); }, + mouseupcaptured: function ( event ) { onMouseUpCaptured( _this, event ); }, + mousemove: function ( event ) { onMouseMove( _this, event ); }, + mousemovecaptured: function ( event ) { onMouseMoveCaptured( _this, event ); }, + + touchstart: function ( event ) { onTouchStart( _this, event ); }, + touchend: function ( event ) { onTouchEnd( _this, event ); }, + touchendcaptured: function ( event ) { onTouchEndCaptured( _this, event ); }, + touchmove: function ( event ) { onTouchMove( _this, event ); }, + touchmovecaptured: function ( event ) { onTouchMoveCaptured( _this, event ); }, + touchcancel: function ( event ) { onTouchCancel( _this, event ); }, + + gesturestart: function ( event ) { onGestureStart( _this, event ); }, + gesturechange: function ( event ) { onGestureChange( _this, event ); }, + + pointerover: function ( event ) { onPointerOver( _this, event ); }, + MSPointerOver: function ( event ) { onPointerOver( _this, event ); }, + pointerout: function ( event ) { onPointerOut( _this, event ); }, + MSPointerOut: function ( event ) { onPointerOut( _this, event ); }, + pointerdown: function ( event ) { onPointerDown( _this, event ); }, + MSPointerDown: function ( event ) { onPointerDown( _this, event ); }, + pointerup: function ( event ) { onPointerUp( _this, event ); }, + MSPointerUp: function ( event ) { onPointerUp( _this, event ); }, + pointermove: function ( event ) { onPointerMove( _this, event ); }, + MSPointerMove: function ( event ) { onPointerMove( _this, event ); }, + pointercancel: function ( event ) { onPointerCancel( _this, event ); }, + MSPointerCancel: function ( event ) { onPointerCancel( _this, event ); }, + pointerupcaptured: function ( event ) { onPointerUpCaptured( _this, event ); }, + pointermovecaptured: function ( event ) { onPointerMoveCaptured( _this, event ); }, + + tracking: false, + + // Active pointers lists. Array of GesturePointList objects, one for each pointer device type. + // GesturePointList objects are added each time a pointer is tracked by a new pointer device type (see getActivePointersListByType()). + // Active pointers are any pointer being tracked for this element which are in the hit-test area + // of the element (for hover-capable devices) and/or have contact or a button press initiated in the element. + activePointersLists: [], + + // Tracking for double-click gesture + lastClickPos: null, + dblClickTimeOut: null, + + // Tracking for pinch gesture + pinchGPoints: [], + lastPinchDist: 0, + currentPinchDist: 0, + lastPinchCenter: null, + currentPinchCenter: null + }; + + if ( !options.startDisabled ) { + this.setTracking( true ); + } + }; + + /** @lends OpenSeadragon.MouseTracker.prototype */ + $.MouseTracker.prototype = { + + /** + * Clean up any events or objects created by the tracker. + * @function + */ + destroy: function () { + var i; + + stopTracking( this ); + this.element = null; + + for ( i = 0; i < MOUSETRACKERS.length; i++ ) { + if ( MOUSETRACKERS[ i ] === this ) { + MOUSETRACKERS.splice( i, 1 ); + break; + } + } + + THIS[ this.hash ] = null; + delete THIS[ this.hash ]; + }, + + /** + * Are we currently tracking events on this element. + * @deprecated Just use this.tracking + * @function + * @returns {Boolean} Are we currently tracking events on this element. + */ + isTracking: function () { + return THIS[ this.hash ].tracking; + }, + + /** + * Enable or disable whether or not we are tracking events on this element. + * @function + * @param {Boolean} track True to start tracking, false to stop tracking. + * @returns {OpenSeadragon.MouseTracker} Chainable. + */ + setTracking: function ( track ) { + if ( track ) { + startTracking( this ); + } else { + stopTracking( this ); + } + //chain + return this; + }, + + /** + * Returns the {@link OpenSeadragon.MouseTracker.GesturePointList|GesturePointList} for all but the given pointer device type. + * @function + * @param {String} type - The pointer device type: "mouse", "touch", "pen", etc. + * @returns {Array.} + */ + getActivePointersListsExceptType: function ( type ) { + var delegate = THIS[ this.hash ]; + var listArray = []; + + for (var i = 0; i < delegate.activePointersLists.length; ++i) { + if (delegate.activePointersLists[i].type !== type) { + listArray.push(delegate.activePointersLists[i]); + } + } + + return listArray; + }, + + /** + * Returns the {@link OpenSeadragon.MouseTracker.GesturePointList|GesturePointList} for the given pointer device type, + * creating and caching a new {@link OpenSeadragon.MouseTracker.GesturePointList|GesturePointList} if one doesn't already exist for the type. + * @function + * @param {String} type - The pointer device type: "mouse", "touch", "pen", etc. + * @returns {OpenSeadragon.MouseTracker.GesturePointList} + */ + getActivePointersListByType: function ( type ) { + var delegate = THIS[ this.hash ], + i, + len = delegate.activePointersLists.length, + list; + + for ( i = 0; i < len; i++ ) { + if ( delegate.activePointersLists[ i ].type === type ) { + return delegate.activePointersLists[ i ]; + } + } + + list = new $.MouseTracker.GesturePointList( type ); + delegate.activePointersLists.push( list ); + return list; + }, + + /** + * Returns the total number of pointers currently active on the tracked element. + * @function + * @returns {Number} + */ + getActivePointerCount: function () { + var delegate = THIS[ this.hash ], + i, + len = delegate.activePointersLists.length, + count = 0; + + for ( i = 0; i < len; i++ ) { + count += delegate.activePointersLists[ i ].getLength(); + } + + return count; + }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Number} event.pointers + * Number of pointers (all types) active in the tracked element. + * @param {Boolean} event.insideElementPressed + * True if the left mouse button is currently being pressed and was + * initiated inside the tracked element, otherwise false. + * @param {Boolean} event.buttonDownAny + * Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + enterHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Number} event.pointers + * Number of pointers (all types) active in the tracked element. + * @param {Boolean} event.insideElementPressed + * True if the left mouse button is currently being pressed and was + * initiated inside the tracked element, otherwise false. + * @param {Boolean} event.buttonDownAny + * Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + exitHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + pressHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.button + * Button which caused the event. + * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + nonPrimaryPressHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Boolean} event.insideElementPressed + * True if the left mouse button is currently being pressed and was + * initiated inside the tracked element, otherwise false. + * @param {Boolean} event.insideElementReleased + * True if the cursor inside the tracked element when the button was released. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + releaseHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.button + * Button which caused the event. + * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + nonPrimaryReleaseHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + moveHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.scroll + * The scroll delta for the event. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. Touch devices no longer generate scroll event. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + scrollHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Boolean} event.quick + * True only if the clickDistThreshold and clickTimeThreshold are both passed. Useful for ignoring drag events. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + clickHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + dblClickHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {OpenSeadragon.Point} event.delta + * The x,y components of the difference between the current position and the last drag event position. Useful for ignoring or weighting the events. + * @param {Number} event.speed + * Current computed speed, in pixels per second. + * @param {Number} event.direction + * Current computed direction, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + dragHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.speed + * Speed at the end of a drag gesture, in pixels per second. + * @param {Number} event.direction + * Direction at the end of a drag gesture, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + dragEndHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {Array.} event.gesturePoints + * Gesture points associated with the gesture. Velocity data can be found here. + * @param {OpenSeadragon.Point} event.lastCenter + * The previous center point of the two pinch contact points relative to the tracked element. + * @param {OpenSeadragon.Point} event.center + * The center point of the two pinch contact points relative to the tracked element. + * @param {Number} event.lastDistance + * The previous distance between the two pinch contact points in CSS pixels. + * @param {Number} event.distance + * The distance between the two pinch contact points in CSS pixels. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + pinchHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + stopHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {Number} event.keyCode + * The key code that was pressed. + * @param {Boolean} event.ctrl + * True if the ctrl key was pressed during this event. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.alt + * True if the alt key was pressed during this event. + * @param {Boolean} event.meta + * True if the meta key was pressed during this event. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + keyDownHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {Number} event.keyCode + * The key code that was pressed. + * @param {Boolean} event.ctrl + * True if the ctrl key was pressed during this event. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.alt + * True if the alt key was pressed during this event. + * @param {Boolean} event.meta + * True if the meta key was pressed during this event. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + keyUpHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {Number} event.keyCode + * The key code that was pressed. + * @param {Boolean} event.ctrl + * True if the ctrl key was pressed during this event. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.alt + * True if the alt key was pressed during this event. + * @param {Boolean} event.meta + * True if the meta key was pressed during this event. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + keyHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + focusHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + blurHandler: function () { } + }; + + /** + * Resets all active mousetrakers. (Added to patch issue #697 "Mouse up outside map will cause "canvas-drag" event to stick") + * + * @private + * @member resetAllMouseTrackers + * @memberof OpenSeadragon.MouseTracker + */ + $.MouseTracker.resetAllMouseTrackers = function(){ + for(var i = 0; i < MOUSETRACKERS.length; i++){ + if (MOUSETRACKERS[i].isTracking()){ + MOUSETRACKERS[i].setTracking(false); + MOUSETRACKERS[i].setTracking(true); + } + } + }; + + /** + * Provides continuous computation of velocity (speed and direction) of active pointers. + * This is a singleton, used by all MouseTracker instances, as it is unlikely there will ever be more than + * two active gesture pointers at a time. + * + * @private + * @member gesturePointVelocityTracker + * @memberof OpenSeadragon.MouseTracker + */ + $.MouseTracker.gesturePointVelocityTracker = (function () { + var trackerPoints = [], + intervalId = 0, + lastTime = 0; + + // Generates a unique identifier for a tracked gesture point + var _generateGuid = function ( tracker, gPoint ) { + return tracker.hash.toString() + gPoint.type + gPoint.id.toString(); + }; + + // Interval timer callback. Computes velocity for all tracked gesture points. + var _doTracking = function () { + var i, + len = trackerPoints.length, + trackPoint, + gPoint, + now = $.now(), + elapsedTime, + distance, + speed; + + elapsedTime = now - lastTime; + lastTime = now; + + for ( i = 0; i < len; i++ ) { + trackPoint = trackerPoints[ i ]; + gPoint = trackPoint.gPoint; + // Math.atan2 gives us just what we need for a velocity vector, as we can simply + // use cos()/sin() to extract the x/y velocity components. + gPoint.direction = Math.atan2( gPoint.currentPos.y - trackPoint.lastPos.y, gPoint.currentPos.x - trackPoint.lastPos.x ); + // speed = distance / elapsed time + distance = trackPoint.lastPos.distanceTo( gPoint.currentPos ); + trackPoint.lastPos = gPoint.currentPos; + speed = 1000 * distance / ( elapsedTime + 1 ); + // Simple biased average, favors the most recent speed computation. Smooths out erratic gestures a bit. + gPoint.speed = 0.75 * speed + 0.25 * gPoint.speed; + } + }; + + // Public. Add a gesture point to be tracked + var addPoint = function ( tracker, gPoint ) { + var guid = _generateGuid( tracker, gPoint ); + + trackerPoints.push( + { + guid: guid, + gPoint: gPoint, + lastPos: gPoint.currentPos + } ); + + // Only fire up the interval timer when there's gesture pointers to track + if ( trackerPoints.length === 1 ) { + lastTime = $.now(); + intervalId = window.setInterval( _doTracking, 50 ); + } + }; + + // Public. Stop tracking a gesture point + var removePoint = function ( tracker, gPoint ) { + var guid = _generateGuid( tracker, gPoint ), + i, + len = trackerPoints.length; + for ( i = 0; i < len; i++ ) { + if ( trackerPoints[ i ].guid === guid ) { + trackerPoints.splice( i, 1 ); + // Only run the interval timer if theres gesture pointers to track + len--; + if ( len === 0 ) { + window.clearInterval( intervalId ); + } + break; + } + } + }; + + return { + addPoint: addPoint, + removePoint: removePoint + }; + } )(); + + +/////////////////////////////////////////////////////////////////////////////// +// Pointer event model and feature detection +/////////////////////////////////////////////////////////////////////////////// + + $.MouseTracker.captureElement = document; + + /** + * Detect available mouse wheel event name. + */ + $.MouseTracker.wheelEventName = ( $.Browser.vendor == $.BROWSERS.IE && $.Browser.version > 8 ) || + ( 'onwheel' in document.createElement( 'div' ) ) ? 'wheel' : // Modern browsers support 'wheel' + document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least 'mousewheel' + 'DOMMouseScroll'; // Assume old Firefox + + /** + * Detect legacy mouse capture support. + */ + $.MouseTracker.supportsMouseCapture = (function () { + var divElement = document.createElement( 'div' ); + return $.isFunction( divElement.setCapture ) && $.isFunction( divElement.releaseCapture ); + }()); + + /** + * Detect browser pointer device event model(s) and build appropriate list of events to subscribe to. + */ + $.MouseTracker.subscribeEvents = [ "click", "dblclick", "keydown", "keyup", "keypress", "focus", "blur", $.MouseTracker.wheelEventName ]; + + if( $.MouseTracker.wheelEventName == "DOMMouseScroll" ) { + // Older Firefox + $.MouseTracker.subscribeEvents.push( "MozMousePixelScroll" ); + } + + // Note: window.navigator.pointerEnable is deprecated on IE 11 and not part of W3C spec. + if ( window.PointerEvent && ( window.navigator.pointerEnabled || $.Browser.vendor !== $.BROWSERS.IE ) ) { + // IE11 and other W3C Pointer Event implementations (see http://www.w3.org/TR/pointerevents) + $.MouseTracker.havePointerEvents = true; + $.MouseTracker.subscribeEvents.push( "pointerover", "pointerout", "pointerdown", "pointerup", "pointermove", "pointercancel" ); + $.MouseTracker.unprefixedPointerEvents = true; + if( navigator.maxTouchPoints ) { + $.MouseTracker.maxTouchPoints = navigator.maxTouchPoints; + } else { + $.MouseTracker.maxTouchPoints = 0; + } + $.MouseTracker.haveMouseEnter = false; + } else if ( window.MSPointerEvent && window.navigator.msPointerEnabled ) { + // IE10 + $.MouseTracker.havePointerEvents = true; + $.MouseTracker.subscribeEvents.push( "MSPointerOver", "MSPointerOut", "MSPointerDown", "MSPointerUp", "MSPointerMove", "MSPointerCancel" ); + $.MouseTracker.unprefixedPointerEvents = false; + if( navigator.msMaxTouchPoints ) { + $.MouseTracker.maxTouchPoints = navigator.msMaxTouchPoints; + } else { + $.MouseTracker.maxTouchPoints = 0; + } + $.MouseTracker.haveMouseEnter = false; + } else { + // Legacy W3C mouse events + $.MouseTracker.havePointerEvents = false; + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + $.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave" ); + $.MouseTracker.haveMouseEnter = true; + } else { + $.MouseTracker.subscribeEvents.push( "mouseover", "mouseout" ); + $.MouseTracker.haveMouseEnter = false; + } + $.MouseTracker.subscribeEvents.push( "mousedown", "mouseup", "mousemove" ); + if ( 'ontouchstart' in window ) { + // iOS, Android, and other W3c Touch Event implementations + // (see http://www.w3.org/TR/touch-events/) + // (see https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html) + // (see https://developer.apple.com/library/safari/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html) + $.MouseTracker.subscribeEvents.push( "touchstart", "touchend", "touchmove", "touchcancel" ); + } + if ( 'ongesturestart' in window ) { + // iOS (see https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html) + // Subscribe to these to prevent default gesture handling + $.MouseTracker.subscribeEvents.push( "gesturestart", "gesturechange" ); + } + $.MouseTracker.mousePointerId = "legacy-mouse"; + $.MouseTracker.maxTouchPoints = 10; + } + + +/////////////////////////////////////////////////////////////////////////////// +// Classes and typedefs +/////////////////////////////////////////////////////////////////////////////// + + /** + * Represents a point of contact on the screen made by a mouse cursor, pen, touch, or other pointer device. + * + * @typedef {Object} GesturePoint + * @memberof OpenSeadragon.MouseTracker + * + * @property {Number} id + * Identifier unique from all other active GesturePoints for a given pointer device. + * @property {String} type + * The pointer device type: "mouse", "touch", "pen", etc. + * @property {Boolean} captured + * True if events for the gesture point are captured to the tracked element. + * @property {Boolean} isPrimary + * True if the gesture point is a master pointer amongst the set of active pointers for each pointer type. True for mouse and primary (first) touch/pen pointers. + * @property {Boolean} insideElementPressed + * True if button pressed or contact point initiated inside the screen area of the tracked element. + * @property {Boolean} insideElement + * True if pointer or contact point is currently inside the bounds of the tracked element. + * @property {Number} speed + * Current computed speed, in pixels per second. + * @property {Number} direction + * Current computed direction, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0. + * @property {OpenSeadragon.Point} contactPos + * The initial pointer contact position, relative to the page including any scrolling. Only valid if the pointer has contact (pressed, touch contact, pen contact). + * @property {Number} contactTime + * The initial pointer contact time, in milliseconds. Only valid if the pointer has contact (pressed, touch contact, pen contact). + * @property {OpenSeadragon.Point} lastPos + * The last pointer position, relative to the page including any scrolling. + * @property {Number} lastTime + * The last pointer contact time, in milliseconds. + * @property {OpenSeadragon.Point} currentPos + * The current pointer position, relative to the page including any scrolling. + * @property {Number} currentTime + * The current pointer contact time, in milliseconds. + */ + + + /** + * @class GesturePointList + * @classdesc Provides an abstraction for a set of active {@link OpenSeadragon.MouseTracker.GesturePoint|GesturePoint} objects for a given pointer device type. + * Active pointers are any pointer being tracked for this element which are in the hit-test area + * of the element (for hover-capable devices) and/or have contact or a button press initiated in the element. + * @memberof OpenSeadragon.MouseTracker + * @param {String} type - The pointer device type: "mouse", "touch", "pen", etc. + */ + $.MouseTracker.GesturePointList = function ( type ) { + this._gPoints = []; + /** + * The pointer device type: "mouse", "touch", "pen", etc. + * @member {String} type + * @memberof OpenSeadragon.MouseTracker.GesturePointList# + */ + this.type = type; + /** + * Current buttons pressed for the device. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @member {Number} buttons + * @memberof OpenSeadragon.MouseTracker.GesturePointList# + */ + this.buttons = 0; + /** + * Current number of contact points (touch points, mouse down, etc.) for the device. + * @member {Number} contacts + * @memberof OpenSeadragon.MouseTracker.GesturePointList# + */ + this.contacts = 0; + /** + * Current number of clicks for the device. Used for multiple click gesture tracking. + * @member {Number} clicks + * @memberof OpenSeadragon.MouseTracker.GesturePointList# + */ + this.clicks = 0; + /** + * Current number of captured pointers for the device. + * @member {Number} captureCount + * @memberof OpenSeadragon.MouseTracker.GesturePointList# + */ + this.captureCount = 0; + }; + + /** @lends OpenSeadragon.MouseTracker.GesturePointList.prototype */ + $.MouseTracker.GesturePointList.prototype = { + /** + * @function + * @returns {Number} Number of gesture points in the list. + */ + getLength: function () { + return this._gPoints.length; + }, + /** + * @function + * @returns {Array.} The list of gesture points in the list as an array (read-only). + */ + asArray: function () { + return this._gPoints; + }, + /** + * @function + * @param {OpenSeadragon.MouseTracker.GesturePoint} gesturePoint - A gesture point to add to the list. + * @returns {Number} Number of gesture points in the list. + */ + add: function ( gp ) { + return this._gPoints.push( gp ); + }, + /** + * @function + * @param {Number} id - The id of the gesture point to remove from the list. + * @returns {Number} Number of gesture points in the list. + */ + removeById: function ( id ) { + var i, + len = this._gPoints.length; + for ( i = 0; i < len; i++ ) { + if ( this._gPoints[ i ].id === id ) { + this._gPoints.splice( i, 1 ); + break; + } + } + return this._gPoints.length; + }, + /** + * @function + * @param {Number} index - The index of the gesture point to retrieve from the list. + * @returns {OpenSeadragon.MouseTracker.GesturePoint|null} The gesture point at the given index, or null if not found. + */ + getByIndex: function ( index ) { + if ( index < this._gPoints.length) { + return this._gPoints[ index ]; + } + + return null; + }, + /** + * @function + * @param {Number} id - The id of the gesture point to retrieve from the list. + * @returns {OpenSeadragon.MouseTracker.GesturePoint|null} The gesture point with the given id, or null if not found. + */ + getById: function ( id ) { + var i, + len = this._gPoints.length; + for ( i = 0; i < len; i++ ) { + if ( this._gPoints[ i ].id === id ) { + return this._gPoints[ i ]; + } + } + return null; + }, + /** + * @function + * @returns {OpenSeadragon.MouseTracker.GesturePoint|null} The primary gesture point in the list, or null if not found. + */ + getPrimary: function ( id ) { + var i, + len = this._gPoints.length; + for ( i = 0; i < len; i++ ) { + if ( this._gPoints[ i ].isPrimary ) { + return this._gPoints[ i ]; + } + } + return null; + }, + + /** + * Increment this pointer's contact count. + * It will evaluate whether this pointer type is allowed to have multiple contacts. + * @function + */ + addContact: function() { + ++this.contacts; + + if (this.contacts > 1 && (this.type === "mouse" || this.type === "pen")) { + this.contacts = 1; + } + }, + + /** + * Decrement this pointer's contact count. + * It will make sure the count does not go below 0. + * @function + */ + removeContact: function() { + --this.contacts; + + if (this.contacts < 0) { + this.contacts = 0; + } + } + }; + + +/////////////////////////////////////////////////////////////////////////////// +// Utility functions +/////////////////////////////////////////////////////////////////////////////// + + /** + * Removes all tracked pointers. + * @private + * @inner + */ + function clearTrackedPointers( tracker ) { + var delegate = THIS[ tracker.hash ], + i, + pointerListCount = delegate.activePointersLists.length; + + for ( i = 0; i < pointerListCount; i++ ) { + if ( delegate.activePointersLists[ i ].captureCount > 0 ) { + $.removeEvent( + $.MouseTracker.captureElement, + 'mousemove', + delegate.mousemovecaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + 'mouseup', + delegate.mouseupcaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove', + delegate.pointermovecaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp', + delegate.pointerupcaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + 'touchmove', + delegate.touchmovecaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + 'touchend', + delegate.touchendcaptured, + true + ); + + delegate.activePointersLists[ i ].captureCount = 0; + } + } + + for ( i = 0; i < pointerListCount; i++ ) { + delegate.activePointersLists.pop(); + } + } + + /** + * Starts tracking pointer events on the tracked element. + * @private + * @inner + */ + function startTracking( tracker ) { + var delegate = THIS[ tracker.hash ], + event, + i; + + if ( !delegate.tracking ) { + for ( i = 0; i < $.MouseTracker.subscribeEvents.length; i++ ) { + event = $.MouseTracker.subscribeEvents[ i ]; + $.addEvent( + tracker.element, + event, + delegate[ event ], + false + ); + } + + clearTrackedPointers( tracker ); + + delegate.tracking = true; + } + } + + /** + * Stops tracking pointer events on the tracked element. + * @private + * @inner + */ + function stopTracking( tracker ) { + var delegate = THIS[ tracker.hash ], + event, + i; + + if ( delegate.tracking ) { + for ( i = 0; i < $.MouseTracker.subscribeEvents.length; i++ ) { + event = $.MouseTracker.subscribeEvents[ i ]; + $.removeEvent( + tracker.element, + event, + delegate[ event ], + false + ); + } + + clearTrackedPointers( tracker ); + + delegate.tracking = false; + } + } + + /** + * @private + * @inner + */ + function getCaptureEventParams( tracker, pointerType ) { + var delegate = THIS[ tracker.hash ]; + + if ( pointerType === 'pointerevent' ) { + return { + upName: $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp', + upHandler: delegate.pointerupcaptured, + moveName: $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove', + moveHandler: delegate.pointermovecaptured + }; + } else if ( pointerType === 'mouse' ) { + return { + upName: 'mouseup', + upHandler: delegate.mouseupcaptured, + moveName: 'mousemove', + moveHandler: delegate.mousemovecaptured + }; + } else if ( pointerType === 'touch' ) { + return { + upName: 'touchend', + upHandler: delegate.touchendcaptured, + moveName: 'touchmove', + moveHandler: delegate.touchmovecaptured + }; + } else { + throw new Error( "MouseTracker.getCaptureEventParams: Unknown pointer type." ); + } + } + + /** + * Begin capturing pointer events to the tracked element. + * @private + * @inner + */ + function capturePointer( tracker, pointerType, pointerCount ) { + var pointsList = tracker.getActivePointersListByType( pointerType ), + eventParams; + + pointsList.captureCount += (pointerCount || 1); + + if ( pointsList.captureCount === 1 ) { + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + tracker.element.setCapture( true ); + } else { + eventParams = getCaptureEventParams( tracker, $.MouseTracker.havePointerEvents ? 'pointerevent' : pointerType ); + // We emulate mouse capture by hanging listeners on the document object. + // (Note we listen on the capture phase so the captured handlers will get called first) + // eslint-disable-next-line no-use-before-define + if (isInIframe && canAccessEvents(window.top)) { + $.addEvent( + window.top, + eventParams.upName, + eventParams.upHandler, + true + ); + } + $.addEvent( + $.MouseTracker.captureElement, + eventParams.upName, + eventParams.upHandler, + true + ); + $.addEvent( + $.MouseTracker.captureElement, + eventParams.moveName, + eventParams.moveHandler, + true + ); + } + } + } + + + /** + * Stop capturing pointer events to the tracked element. + * @private + * @inner + */ + function releasePointer( tracker, pointerType, pointerCount ) { + var pointsList = tracker.getActivePointersListByType( pointerType ), + eventParams; + + pointsList.captureCount -= (pointerCount || 1); + + if ( pointsList.captureCount === 0 ) { + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + tracker.element.releaseCapture(); + } else { + eventParams = getCaptureEventParams( tracker, $.MouseTracker.havePointerEvents ? 'pointerevent' : pointerType ); + // We emulate mouse capture by hanging listeners on the document object. + // (Note we listen on the capture phase so the captured handlers will get called first) + // eslint-disable-next-line no-use-before-define + if (isInIframe && canAccessEvents(window.top)) { + $.removeEvent( + window.top, + eventParams.upName, + eventParams.upHandler, + true + ); + } + $.removeEvent( + $.MouseTracker.captureElement, + eventParams.moveName, + eventParams.moveHandler, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + eventParams.upName, + eventParams.upHandler, + true + ); + } + } + } + + + /** + * Gets a W3C Pointer Events model compatible pointer type string from a DOM pointer event. + * IE10 used a long integer value, but the W3C specification (and IE11+) use a string "mouse", "touch", "pen", etc. + * @private + * @inner + */ + function getPointerType( event ) { + var pointerTypeStr; + if ( $.MouseTracker.unprefixedPointerEvents ) { + pointerTypeStr = event.pointerType; + } else { + // IE10 + // MSPOINTER_TYPE_TOUCH: 0x00000002 + // MSPOINTER_TYPE_PEN: 0x00000003 + // MSPOINTER_TYPE_MOUSE: 0x00000004 + switch( event.pointerType ) + { + case 0x00000002: + pointerTypeStr = 'touch'; + break; + case 0x00000003: + pointerTypeStr = 'pen'; + break; + case 0x00000004: + pointerTypeStr = 'mouse'; + break; + default: + pointerTypeStr = ''; + } + } + return pointerTypeStr; + } + + + /** + * @private + * @inner + */ + function getMouseAbsolute( event ) { + return $.getMousePosition( event ); + } + + /** + * @private + * @inner + */ + function getMouseRelative( event, element ) { + return getPointRelativeToAbsolute( getMouseAbsolute( event ), element ); + } + + /** + * @private + * @inner + */ + function getPointRelativeToAbsolute( point, element ) { + var offset = $.getElementOffset( element ); + return point.minus( offset ); + } + + /** + * @private + * @inner + */ + function getCenterPoint( point1, point2 ) { + return new $.Point( ( point1.x + point2.x ) / 2, ( point1.y + point2.y ) / 2 ); + } + + +/////////////////////////////////////////////////////////////////////////////// +// Device-specific DOM event handlers +/////////////////////////////////////////////////////////////////////////////// + + /** + * @private + * @inner + */ + function onClick( tracker, event ) { + if ( tracker.clickHandler ) { + $.cancelEvent( event ); + } + } + + + /** + * @private + * @inner + */ + function onDblClick( tracker, event ) { + if ( tracker.dblClickHandler ) { + $.cancelEvent( event ); + } + } + + + /** + * @private + * @inner + */ + function onKeyDown( tracker, event ) { + //$.console.log( "keydown %s %s %s %s %s", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey ); + var propagate; + if ( tracker.keyDownHandler ) { + event = $.getEvent( event ); + propagate = tracker.keyDownHandler( + { + eventSource: tracker, + keyCode: event.keyCode ? event.keyCode : event.charCode, + ctrl: event.ctrlKey, + shift: event.shiftKey, + alt: event.altKey, + meta: event.metaKey, + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( !propagate ) { + $.cancelEvent( event ); + } + } + } + + + /** + * @private + * @inner + */ + function onKeyUp( tracker, event ) { + //$.console.log( "keyup %s %s %s %s %s", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey ); + var propagate; + if ( tracker.keyUpHandler ) { + event = $.getEvent( event ); + propagate = tracker.keyUpHandler( + { + eventSource: tracker, + keyCode: event.keyCode ? event.keyCode : event.charCode, + ctrl: event.ctrlKey, + shift: event.shiftKey, + alt: event.altKey, + meta: event.metaKey, + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( !propagate ) { + $.cancelEvent( event ); + } + } + } + + + /** + * @private + * @inner + */ + function onKeyPress( tracker, event ) { + //$.console.log( "keypress %s %s %s %s %s", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey ); + var propagate; + if ( tracker.keyHandler ) { + event = $.getEvent( event ); + propagate = tracker.keyHandler( + { + eventSource: tracker, + keyCode: event.keyCode ? event.keyCode : event.charCode, + ctrl: event.ctrlKey, + shift: event.shiftKey, + alt: event.altKey, + meta: event.metaKey, + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( !propagate ) { + $.cancelEvent( event ); + } + } + } + + + /** + * @private + * @inner + */ + function onFocus( tracker, event ) { + //console.log( "focus %s", event ); + var propagate; + if ( tracker.focusHandler ) { + event = $.getEvent( event ); + propagate = tracker.focusHandler( + { + eventSource: tracker, + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } + + + /** + * @private + * @inner + */ + function onBlur( tracker, event ) { + //console.log( "blur %s", event ); + var propagate; + if ( tracker.blurHandler ) { + event = $.getEvent( event ); + propagate = tracker.blurHandler( + { + eventSource: tracker, + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } + + + /** + * Handler for 'wheel' events + * + * @private + * @inner + */ + function onWheel( tracker, event ) { + handleWheelEvent( tracker, event, event ); + } + + + /** + * Handler for 'mousewheel', 'DOMMouseScroll', and 'MozMousePixelScroll' events + * + * @private + * @inner + */ + function onMouseWheel( tracker, event ) { + event = $.getEvent( event ); + + // Simulate a 'wheel' event + var simulatedEvent = { + target: event.target || event.srcElement, + type: "wheel", + shiftKey: event.shiftKey || false, + clientX: event.clientX, + clientY: event.clientY, + pageX: event.pageX ? event.pageX : event.clientX, + pageY: event.pageY ? event.pageY : event.clientY, + deltaMode: event.type == "MozMousePixelScroll" ? 0 : 1, // 0=pixel, 1=line, 2=page + deltaX: 0, + deltaZ: 0 + }; + + // Calculate deltaY + if ( $.MouseTracker.wheelEventName == "mousewheel" ) { + simulatedEvent.deltaY = -event.wheelDelta / $.DEFAULT_SETTINGS.pixelsPerWheelLine; + } else { + simulatedEvent.deltaY = event.detail; + } + + handleWheelEvent( tracker, simulatedEvent, event ); + } + + + /** + * Handles 'wheel' events. + * The event may be simulated by the legacy mouse wheel event handler (onMouseWheel()). + * + * @private + * @inner + */ + function handleWheelEvent( tracker, event, originalEvent ) { + var nDelta = 0, + propagate; + + // The nDelta variable is gated to provide smooth z-index scrolling + // since the mouse wheel allows for substantial deltas meant for rapid + // y-index scrolling. + // event.deltaMode: 0=pixel, 1=line, 2=page + // TODO: Deltas in pixel mode should be accumulated then a scroll value computed after $.DEFAULT_SETTINGS.pixelsPerWheelLine threshold reached + nDelta = event.deltaY < 0 ? 1 : -1; + + if ( tracker.scrollHandler ) { + propagate = tracker.scrollHandler( + { + eventSource: tracker, + pointerType: 'mouse', + position: getMouseRelative( event, tracker.element ), + scroll: nDelta, + shift: event.shiftKey, + isTouchEvent: false, + originalEvent: originalEvent, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( originalEvent ); + } + } + } + + + /** + * @private + * @inner + */ + function isParentChild( parent, child ) + { + if ( parent === child ) { + return false; + } + while ( child && child !== parent ) { + child = child.parentNode; + } + return child === parent; + } + + + /** + * Only used on IE 8 + * + * @private + * @inner + */ + function onMouseEnter( tracker, event ) { + event = $.getEvent( event ); + + handleMouseEnter( tracker, event ); + } + + + /** + * @private + * @inner + */ + function onMouseOver( tracker, event ) { + event = $.getEvent( event ); + + if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { + return; + } + + handleMouseEnter( tracker, event ); + } + + + /** + * @private + * @inner + */ + function handleMouseEnter( tracker, event ) { + var gPoint = { + id: $.MouseTracker.mousePointerId, + type: 'mouse', + isPrimary: true, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + updatePointersEnter( tracker, event, [ gPoint ] ); + } + + + /** + * Only used on IE 8 + * + * @private + * @inner + */ + function onMouseLeave( tracker, event ) { + event = $.getEvent( event ); + + handleMouseExit( tracker, event ); + } + + + /** + * @private + * @inner + */ + function onMouseOut( tracker, event ) { + event = $.getEvent( event ); + + if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { + return; + } + + handleMouseExit( tracker, event ); + } + + + /** + * @private + * @inner + */ + function handleMouseExit( tracker, event ) { + var gPoint = { + id: $.MouseTracker.mousePointerId, + type: 'mouse', + isPrimary: true, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + updatePointersExit( tracker, event, [ gPoint ] ); + } + + + /** + * Returns a W3C DOM level 3 standard button value given an event.button property: + * -1 == none, 0 == primary/left, 1 == middle, 2 == secondary/right, 3 == X1/back, 4 == X2/forward, 5 == eraser (pen) + * @private + * @inner + */ + function getStandardizedButton( button ) { + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + // On IE 8, 0 == none, 1 == left, 2 == right, 3 == left and right, 4 == middle, 5 == left and middle, 6 == right and middle, 7 == all three + // TODO: Support chorded (multiple) button presses on IE 8? + if ( button === 1 ) { + return 0; + } else if ( button === 2 ) { + return 2; + } else if ( button === 4 ) { + return 1; + } else { + return -1; + } + } else { + return button; + } + } + + + /** + * @private + * @inner + */ + function onMouseDown( tracker, event ) { + var gPoint; + + event = $.getEvent( event ); + + gPoint = { + id: $.MouseTracker.mousePointerId, + type: 'mouse', + isPrimary: true, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + if ( updatePointersDown( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) { + $.stopEvent( event ); + capturePointer( tracker, 'mouse' ); + } + + if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler ) { + $.cancelEvent( event ); + } + } + + + /** + * @private + * @inner + */ + function onMouseUp( tracker, event ) { + handleMouseUp( tracker, event ); + } + + /** + * This handler is attached to the window object (on the capture phase) to emulate mouse capture. + * onMouseUp is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onMouseUpCaptured( tracker, event ) { + handleMouseUp( tracker, event ); + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handleMouseUp( tracker, event ) { + var gPoint; + + event = $.getEvent( event ); + + gPoint = { + id: $.MouseTracker.mousePointerId, + type: 'mouse', + isPrimary: true, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + if ( updatePointersUp( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) { + releasePointer( tracker, 'mouse' ); + } + } + + + /** + * @private + * @inner + */ + function onMouseMove( tracker, event ) { + handleMouseMove( tracker, event ); + } + + + /** + * This handler is attached to the window object (on the capture phase) to emulate mouse capture. + * onMouseMove is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onMouseMoveCaptured( tracker, event ) { + handleMouseMove( tracker, event ); + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handleMouseMove( tracker, event ) { + var gPoint; + + event = $.getEvent( event ); + + gPoint = { + id: $.MouseTracker.mousePointerId, + type: 'mouse', + isPrimary: true, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + updatePointersMove( tracker, event, [ gPoint ] ); + } + + + /** + * @private + * @inner + */ + function abortContacts( tracker, event, pointsList ) { + var i, + gPointCount = pointsList.getLength(), + abortGPoints = []; + + // Check contact count for hoverable pointer types before aborting + if (pointsList.type === 'touch' || pointsList.contacts > 0) { + for ( i = 0; i < gPointCount; i++ ) { + abortGPoints.push( pointsList.getByIndex( i ) ); + } + + if ( abortGPoints.length > 0 ) { + // simulate touchend/mouseup + updatePointersUp( tracker, event, abortGPoints, 0 ); // 0 means primary button press/release or touch contact + // release pointer capture + pointsList.captureCount = 1; + releasePointer( tracker, pointsList.type ); + // simulate touchleave/mouseout + updatePointersExit( tracker, event, abortGPoints ); + } + } + } + + + /** + * @private + * @inner + */ + function onTouchStart( tracker, event ) { + var time, + i, + j, + touchCount = event.changedTouches.length, + gPoints = [], + parentGPoints, + pointsList = tracker.getActivePointersListByType( 'touch' ); + + time = $.now(); + + if ( pointsList.getLength() > event.touches.length - touchCount ) { + $.console.warn('Tracked touch contact count doesn\'t match event.touches.length. Removing all tracked touch pointers.'); + abortContacts( tracker, event, pointsList ); + } + + for ( i = 0; i < touchCount; i++ ) { + gPoints.push( { + id: event.changedTouches[ i ].identifier, + type: 'touch', + // isPrimary not set - let the updatePointers functions determine it + currentPos: getMouseAbsolute( event.changedTouches[ i ] ), + currentTime: time + } ); + } + + // simulate touchenter on our tracked element + updatePointersEnter( tracker, event, gPoints ); + + // simulate touchenter on our tracked element's tracked ancestor elements + for ( i = 0; i < MOUSETRACKERS.length; i++ ) { + if ( MOUSETRACKERS[ i ] !== tracker && MOUSETRACKERS[ i ].isTracking() && isParentChild( MOUSETRACKERS[ i ].element, tracker.element ) ) { + parentGPoints = []; + for ( j = 0; j < touchCount; j++ ) { + parentGPoints.push( { + id: event.changedTouches[ j ].identifier, + type: 'touch', + // isPrimary not set - let the updatePointers functions determine it + currentPos: getMouseAbsolute( event.changedTouches[ j ] ), + currentTime: time + } ); + } + updatePointersEnter( MOUSETRACKERS[ i ], event, parentGPoints ); + } + } + + if ( updatePointersDown( tracker, event, gPoints, 0 ) ) { // 0 means primary button press/release or touch contact + $.stopEvent( event ); + capturePointer( tracker, 'touch', touchCount ); + } + + $.cancelEvent( event ); + } + + + /** + * @private + * @inner + */ + function onTouchEnd( tracker, event ) { + handleTouchEnd( tracker, event ); + } + + + /** + * This handler is attached to the window object (on the capture phase) to emulate pointer capture. + * onTouchEnd is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onTouchEndCaptured( tracker, event ) { + handleTouchEnd( tracker, event ); + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handleTouchEnd( tracker, event ) { + var time, + i, + j, + touchCount = event.changedTouches.length, + gPoints = [], + parentGPoints; + + time = $.now(); + + for ( i = 0; i < touchCount; i++ ) { + gPoints.push( { + id: event.changedTouches[ i ].identifier, + type: 'touch', + // isPrimary not set - let the updatePointers functions determine it + currentPos: getMouseAbsolute( event.changedTouches[ i ] ), + currentTime: time + } ); + } + + if ( updatePointersUp( tracker, event, gPoints, 0 ) ) { + releasePointer( tracker, 'touch', touchCount ); + } + + // simulate touchleave on our tracked element + updatePointersExit( tracker, event, gPoints ); + + // simulate touchleave on our tracked element's tracked ancestor elements + for ( i = 0; i < MOUSETRACKERS.length; i++ ) { + if ( MOUSETRACKERS[ i ] !== tracker && MOUSETRACKERS[ i ].isTracking() && isParentChild( MOUSETRACKERS[ i ].element, tracker.element ) ) { + parentGPoints = []; + for ( j = 0; j < touchCount; j++ ) { + parentGPoints.push( { + id: event.changedTouches[ j ].identifier, + type: 'touch', + // isPrimary not set - let the updatePointers functions determine it + currentPos: getMouseAbsolute( event.changedTouches[ j ] ), + currentTime: time + } ); + } + updatePointersExit( MOUSETRACKERS[ i ], event, parentGPoints ); + } + } + + $.cancelEvent( event ); + } + + + /** + * @private + * @inner + */ + function onTouchMove( tracker, event ) { + handleTouchMove( tracker, event ); + } + + + /** + * This handler is attached to the window object (on the capture phase) to emulate pointer capture. + * onTouchMove is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onTouchMoveCaptured( tracker, event ) { + handleTouchMove( tracker, event ); + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handleTouchMove( tracker, event ) { + var i, + touchCount = event.changedTouches.length, + gPoints = []; + + for ( i = 0; i < touchCount; i++ ) { + gPoints.push( { + id: event.changedTouches[ i ].identifier, + type: 'touch', + // isPrimary not set - let the updatePointers functions determine it + currentPos: getMouseAbsolute( event.changedTouches[ i ] ), + currentTime: $.now() + } ); + } + + updatePointersMove( tracker, event, gPoints ); + + $.cancelEvent( event ); + } + + + /** + * @private + * @inner + */ + function onTouchCancel( tracker, event ) { + var pointsList = tracker.getActivePointersListByType('touch'); + + abortContacts( tracker, event, pointsList ); + } + + + /** + * @private + * @inner + */ + function onGestureStart( tracker, event ) { + event.stopPropagation(); + event.preventDefault(); + return false; + } + + + /** + * @private + * @inner + */ + function onGestureChange( tracker, event ) { + event.stopPropagation(); + event.preventDefault(); + return false; + } + + + /** + * @private + * @inner + */ + function onPointerOver( tracker, event ) { + var gPoint; + + if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { + return; + } + + gPoint = { + id: event.pointerId, + type: getPointerType( event ), + isPrimary: event.isPrimary, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + updatePointersEnter( tracker, event, [ gPoint ] ); + } + + + /** + * @private + * @inner + */ + function onPointerOut( tracker, event ) { + var gPoint; + + if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { + return; + } + + gPoint = { + id: event.pointerId, + type: getPointerType( event ), + isPrimary: event.isPrimary, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + updatePointersExit( tracker, event, [ gPoint ] ); + } + + + /** + * @private + * @inner + */ + function onPointerDown( tracker, event ) { + var gPoint; + + gPoint = { + id: event.pointerId, + type: getPointerType( event ), + isPrimary: event.isPrimary, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) { + $.stopEvent( event ); + capturePointer( tracker, gPoint.type ); + } + + if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { + $.cancelEvent( event ); + } + } + + + /** + * @private + * @inner + */ + function onPointerUp( tracker, event ) { + handlePointerUp( tracker, event ); + } + + + /** + * This handler is attached to the window object (on the capture phase) to emulate mouse capture. + * onPointerUp is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onPointerUpCaptured( tracker, event ) { + var pointsList = tracker.getActivePointersListByType( getPointerType( event ) ); + if ( pointsList.getById( event.pointerId ) ) { + handlePointerUp( tracker, event ); + } + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handlePointerUp( tracker, event ) { + var gPoint; + + gPoint = { + id: event.pointerId, + type: getPointerType( event ), + isPrimary: event.isPrimary, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) { + releasePointer( tracker, gPoint.type ); + } + } + + + /** + * @private + * @inner + */ + function onPointerMove( tracker, event ) { + handlePointerMove( tracker, event ); + } + + + /** + * This handler is attached to the window object (on the capture phase) to emulate mouse capture. + * onPointerMove is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onPointerMoveCaptured( tracker, event ) { + var pointsList = tracker.getActivePointersListByType( getPointerType( event ) ); + if ( pointsList.getById( event.pointerId ) ) { + handlePointerMove( tracker, event ); + } + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handlePointerMove( tracker, event ) { + // Pointer changed coordinates, button state, pressure, tilt, or contact geometry (e.g. width and height) + var gPoint; + + gPoint = { + id: event.pointerId, + type: getPointerType( event ), + isPrimary: event.isPrimary, + currentPos: getMouseAbsolute( event ), + currentTime: $.now() + }; + + updatePointersMove( tracker, event, [ gPoint ] ); + } + + + /** + * @private + * @inner + */ + function onPointerCancel( tracker, event ) { + var gPoint; + + gPoint = { + id: event.pointerId, + type: getPointerType( event ) + }; + + updatePointersCancel( tracker, event, [ gPoint ] ); + } + + +/////////////////////////////////////////////////////////////////////////////// +// Device-agnostic DOM event handlers +/////////////////////////////////////////////////////////////////////////////// + + /** + * @function + * @private + * @inner + * @param {OpenSeadragon.MouseTracker.GesturePointList} pointsList + * The GesturePointList to track the pointer in. + * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint + * Gesture point to track. + * @returns {Number} Number of gesture points in pointsList. + */ + function startTrackingPointer( pointsList, gPoint ) { + + // If isPrimary is not known for the pointer then set it according to our rules: + // true if the first pointer in the gesture, otherwise false + if ( !gPoint.hasOwnProperty( 'isPrimary' ) ) { + if ( pointsList.getLength() === 0 ) { + gPoint.isPrimary = true; + } else { + gPoint.isPrimary = false; + } + } + gPoint.speed = 0; + gPoint.direction = 0; + gPoint.contactPos = gPoint.currentPos; + gPoint.contactTime = gPoint.currentTime; + gPoint.lastPos = gPoint.currentPos; + gPoint.lastTime = gPoint.currentTime; + + return pointsList.add( gPoint ); + } + + + /** + * @function + * @private + * @inner + * @param {OpenSeadragon.MouseTracker.GesturePointList} pointsList + * The GesturePointList to stop tracking the pointer on. + * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint + * Gesture point to stop tracking. + * @returns {Number} Number of gesture points in pointsList. + */ + function stopTrackingPointer( pointsList, gPoint ) { + var listLength, + primaryPoint; + + if ( pointsList.getById( gPoint.id ) ) { + listLength = pointsList.removeById( gPoint.id ); + + // If isPrimary is not known for the pointer and we just removed the primary pointer from the list then we need to set another pointer as primary + if ( !gPoint.hasOwnProperty( 'isPrimary' ) ) { + primaryPoint = pointsList.getPrimary(); + if ( !primaryPoint ) { + primaryPoint = pointsList.getByIndex( 0 ); + if ( primaryPoint ) { + primaryPoint.isPrimary = true; + } + } + } + } else { + listLength = pointsList.getLength(); + } + + return listLength; + } + + + /** + * @function + * @private + * @inner + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the MouseTracker instance. + * @param {Object} event + * A reference to the originating DOM event. + * @param {Array.} gPoints + * Gesture points associated with the event. + */ + function updatePointersEnter( tracker, event, gPoints ) { + var pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ), + i, + gPointCount = gPoints.length, + curGPoint, + updateGPoint, + propagate; + + for ( i = 0; i < gPointCount; i++ ) { + curGPoint = gPoints[ i ]; + updateGPoint = pointsList.getById( curGPoint.id ); + + if ( updateGPoint ) { + // Already tracking the pointer...update it + updateGPoint.insideElement = true; + updateGPoint.lastPos = updateGPoint.currentPos; + updateGPoint.lastTime = updateGPoint.currentTime; + updateGPoint.currentPos = curGPoint.currentPos; + updateGPoint.currentTime = curGPoint.currentTime; + + curGPoint = updateGPoint; + } else { + // Initialize for tracking and add to the tracking list + curGPoint.captured = false; + curGPoint.insideElementPressed = false; + curGPoint.insideElement = true; + startTrackingPointer( pointsList, curGPoint ); + } + + // Enter + if ( tracker.enterHandler ) { + propagate = tracker.enterHandler( + { + eventSource: tracker, + pointerType: curGPoint.type, + position: getPointRelativeToAbsolute( curGPoint.currentPos, tracker.element ), + buttons: pointsList.buttons, + pointers: tracker.getActivePointerCount(), + insideElementPressed: curGPoint.insideElementPressed, + buttonDownAny: pointsList.buttons !== 0, + isTouchEvent: curGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } + } + + + /** + * @function + * @private + * @inner + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the MouseTracker instance. + * @param {Object} event + * A reference to the originating DOM event. + * @param {Array.} gPoints + * Gesture points associated with the event. + */ + function updatePointersExit( tracker, event, gPoints ) { + var pointsList = tracker.getActivePointersListByType(gPoints[0].type), + i, + gPointCount = gPoints.length, + curGPoint, + updateGPoint, + propagate; + + for ( i = 0; i < gPointCount; i++ ) { + curGPoint = gPoints[ i ]; + updateGPoint = pointsList.getById( curGPoint.id ); + + if ( updateGPoint ) { + // Already tracking the pointer. If captured then update it, else stop tracking it + if ( updateGPoint.captured ) { + updateGPoint.insideElement = false; + updateGPoint.lastPos = updateGPoint.currentPos; + updateGPoint.lastTime = updateGPoint.currentTime; + updateGPoint.currentPos = curGPoint.currentPos; + updateGPoint.currentTime = curGPoint.currentTime; + } else { + stopTrackingPointer( pointsList, updateGPoint ); + } + + curGPoint = updateGPoint; + } + + // Exit + if ( tracker.exitHandler ) { + propagate = tracker.exitHandler( + { + eventSource: tracker, + pointerType: curGPoint.type, + position: getPointRelativeToAbsolute( curGPoint.currentPos, tracker.element ), + buttons: pointsList.buttons, + pointers: tracker.getActivePointerCount(), + insideElementPressed: updateGPoint ? updateGPoint.insideElementPressed : false, + buttonDownAny: pointsList.buttons !== 0, + isTouchEvent: curGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } + } + + + /** + * @function + * @private + * @inner + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the MouseTracker instance. + * @param {Object} event + * A reference to the originating DOM event. + * @param {Array.} gPoints + * Gesture points associated with the event. + * @param {Number} buttonChanged + * The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. + * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model, + * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events. + * + * @returns {Boolean} True if pointers should be captured to the tracked element, otherwise false. + */ + function updatePointersDown( tracker, event, gPoints, buttonChanged ) { + var delegate = THIS[ tracker.hash ], + propagate, + pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ), + i, + gPointCount = gPoints.length, + curGPoint, + updateGPoint; + + if ( typeof event.buttons !== 'undefined' ) { + pointsList.buttons = event.buttons; + } else { + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + if ( buttonChanged === 0 ) { + // Primary + pointsList.buttons += 1; + } else if ( buttonChanged === 1 ) { + // Aux + pointsList.buttons += 4; + } else if ( buttonChanged === 2 ) { + // Secondary + pointsList.buttons += 2; + } else if ( buttonChanged === 3 ) { + // X1 (Back) + pointsList.buttons += 8; + } else if ( buttonChanged === 4 ) { + // X2 (Forward) + pointsList.buttons += 16; + } else if ( buttonChanged === 5 ) { + // Pen Eraser + pointsList.buttons += 32; + } + } else { + if ( buttonChanged === 0 ) { + // Primary + pointsList.buttons |= 1; + } else if ( buttonChanged === 1 ) { + // Aux + pointsList.buttons |= 4; + } else if ( buttonChanged === 2 ) { + // Secondary + pointsList.buttons |= 2; + } else if ( buttonChanged === 3 ) { + // X1 (Back) + pointsList.buttons |= 8; + } else if ( buttonChanged === 4 ) { + // X2 (Forward) + pointsList.buttons |= 16; + } else if ( buttonChanged === 5 ) { + // Pen Eraser + pointsList.buttons |= 32; + } + } + } + + // Some pointers may steal control from another pointer without firing the appropriate release events + // e.g. Touching a screen while click-dragging with certain mice. + var otherPointsLists = tracker.getActivePointersListsExceptType(gPoints[ 0 ].type); + for (i = 0; i < otherPointsLists.length; i++) { + //If another pointer has contact, simulate the release + abortContacts(tracker, event, otherPointsLists[i]); // No-op if no active pointer + } + + // Only capture and track primary button, pen, and touch contacts + if ( buttonChanged !== 0 ) { + // Aux Press + if ( tracker.nonPrimaryPressHandler ) { + propagate = tracker.nonPrimaryPressHandler( + { + eventSource: tracker, + pointerType: gPoints[ 0 ].type, + position: getPointRelativeToAbsolute( gPoints[ 0 ].currentPos, tracker.element ), + button: buttonChanged, + buttons: pointsList.buttons, + isTouchEvent: gPoints[ 0 ].type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + + return false; + } + + for ( i = 0; i < gPointCount; i++ ) { + curGPoint = gPoints[ i ]; + updateGPoint = pointsList.getById( curGPoint.id ); + + if ( updateGPoint ) { + // Already tracking the pointer...update it + updateGPoint.captured = true; + updateGPoint.insideElementPressed = true; + updateGPoint.insideElement = true; + updateGPoint.contactPos = curGPoint.currentPos; + updateGPoint.contactTime = curGPoint.currentTime; + updateGPoint.lastPos = updateGPoint.currentPos; + updateGPoint.lastTime = updateGPoint.currentTime; + updateGPoint.currentPos = curGPoint.currentPos; + updateGPoint.currentTime = curGPoint.currentTime; + + curGPoint = updateGPoint; + } else { + // Initialize for tracking and add to the tracking list (no pointerover or pointermove event occurred before this) + curGPoint.captured = true; + curGPoint.insideElementPressed = true; + curGPoint.insideElement = true; + startTrackingPointer( pointsList, curGPoint ); + } + + pointsList.addContact(); + //$.console.log('contacts++ ', pointsList.contacts); + + if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { + $.MouseTracker.gesturePointVelocityTracker.addPoint( tracker, curGPoint ); + } + + if ( pointsList.contacts === 1 ) { + // Press + if ( tracker.pressHandler ) { + propagate = tracker.pressHandler( + { + eventSource: tracker, + pointerType: curGPoint.type, + position: getPointRelativeToAbsolute( curGPoint.contactPos, tracker.element ), + buttons: pointsList.buttons, + isTouchEvent: curGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } else if ( pointsList.contacts === 2 ) { + if ( tracker.pinchHandler && curGPoint.type === 'touch' ) { + // Initialize for pinch + delegate.pinchGPoints = pointsList.asArray(); + delegate.lastPinchDist = delegate.currentPinchDist = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos ); + delegate.lastPinchCenter = delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos ); + } + } + } + + return true; + } + + + /** + * @function + * @private + * @inner + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the MouseTracker instance. + * @param {Object} event + * A reference to the originating DOM event. + * @param {Array.} gPoints + * Gesture points associated with the event. + * @param {Number} buttonChanged + * The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. + * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model, + * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events. + * + * @returns {Boolean} True if pointer capture should be released from the tracked element, otherwise false. + */ + function updatePointersUp( tracker, event, gPoints, buttonChanged ) { + var delegate = THIS[ tracker.hash ], + pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ), + propagate, + releasePoint, + releaseTime, + i, + gPointCount = gPoints.length, + curGPoint, + updateGPoint, + releaseCapture = false, + wasCaptured = false, + quick; + + if ( typeof event.buttons !== 'undefined' ) { + pointsList.buttons = event.buttons; + } else { + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + if ( buttonChanged === 0 ) { + // Primary + pointsList.buttons -= 1; + } else if ( buttonChanged === 1 ) { + // Aux + pointsList.buttons -= 4; + } else if ( buttonChanged === 2 ) { + // Secondary + pointsList.buttons -= 2; + } else if ( buttonChanged === 3 ) { + // X1 (Back) + pointsList.buttons -= 8; + } else if ( buttonChanged === 4 ) { + // X2 (Forward) + pointsList.buttons -= 16; + } else if ( buttonChanged === 5 ) { + // Pen Eraser + pointsList.buttons -= 32; + } + } else { + if ( buttonChanged === 0 ) { + // Primary + pointsList.buttons ^= ~1; + } else if ( buttonChanged === 1 ) { + // Aux + pointsList.buttons ^= ~4; + } else if ( buttonChanged === 2 ) { + // Secondary + pointsList.buttons ^= ~2; + } else if ( buttonChanged === 3 ) { + // X1 (Back) + pointsList.buttons ^= ~8; + } else if ( buttonChanged === 4 ) { + // X2 (Forward) + pointsList.buttons ^= ~16; + } else if ( buttonChanged === 5 ) { + // Pen Eraser + pointsList.buttons ^= ~32; + } + } + } + + // Only capture and track primary button, pen, and touch contacts + if ( buttonChanged !== 0 ) { + // Aux Release + if ( tracker.nonPrimaryReleaseHandler ) { + propagate = tracker.nonPrimaryReleaseHandler( + { + eventSource: tracker, + pointerType: gPoints[ 0 ].type, + position: getPointRelativeToAbsolute(gPoints[0].currentPos, tracker.element), + button: buttonChanged, + buttons: pointsList.buttons, + isTouchEvent: gPoints[ 0 ].type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + + // A primary mouse button may have been released while the non-primary button was down + var otherPointsList = tracker.getActivePointersListByType("mouse"); + // Stop tracking the mouse; see https://github.com/openseadragon/openseadragon/pull/1223 + abortContacts(tracker, event, otherPointsList); // No-op if no active pointer + + return false; + } + + for ( i = 0; i < gPointCount; i++ ) { + curGPoint = gPoints[ i ]; + updateGPoint = pointsList.getById( curGPoint.id ); + + if ( updateGPoint ) { + // Update the pointer, stop tracking it if not still in this element + if ( updateGPoint.captured ) { + updateGPoint.captured = false; + releaseCapture = true; + wasCaptured = true; + } + updateGPoint.lastPos = updateGPoint.currentPos; + updateGPoint.lastTime = updateGPoint.currentTime; + updateGPoint.currentPos = curGPoint.currentPos; + updateGPoint.currentTime = curGPoint.currentTime; + if ( !updateGPoint.insideElement ) { + stopTrackingPointer( pointsList, updateGPoint ); + } + + releasePoint = updateGPoint.currentPos; + releaseTime = updateGPoint.currentTime; + + if ( wasCaptured ) { + // Pointer was activated in our element but could have been removed in any element since events are captured to our element + + pointsList.removeContact(); + //$.console.log('contacts-- ', pointsList.contacts); + + if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { + $.MouseTracker.gesturePointVelocityTracker.removePoint( tracker, updateGPoint ); + } + + if ( pointsList.contacts === 0 ) { + + // Release (pressed in our element) + if ( tracker.releaseHandler ) { + propagate = tracker.releaseHandler( + { + eventSource: tracker, + pointerType: updateGPoint.type, + position: getPointRelativeToAbsolute( releasePoint, tracker.element ), + buttons: pointsList.buttons, + insideElementPressed: updateGPoint.insideElementPressed, + insideElementReleased: updateGPoint.insideElement, + isTouchEvent: updateGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + + // Drag End + if ( tracker.dragEndHandler && !updateGPoint.currentPos.equals( updateGPoint.contactPos ) ) { + propagate = tracker.dragEndHandler( + { + eventSource: tracker, + pointerType: updateGPoint.type, + position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ), + speed: updateGPoint.speed, + direction: updateGPoint.direction, + shift: event.shiftKey, + isTouchEvent: updateGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + + // Click / Double-Click + if ( ( tracker.clickHandler || tracker.dblClickHandler ) && updateGPoint.insideElement ) { + quick = releaseTime - updateGPoint.contactTime <= tracker.clickTimeThreshold && + updateGPoint.contactPos.distanceTo( releasePoint ) <= tracker.clickDistThreshold; + + // Click + if ( tracker.clickHandler ) { + propagate = tracker.clickHandler( + { + eventSource: tracker, + pointerType: updateGPoint.type, + position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ), + quick: quick, + shift: event.shiftKey, + isTouchEvent: updateGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + + // Double-Click + if ( tracker.dblClickHandler && quick ) { + pointsList.clicks++; + if ( pointsList.clicks === 1 ) { + delegate.lastClickPos = releasePoint; + /*jshint loopfunc:true*/ + delegate.dblClickTimeOut = setTimeout( function() { + pointsList.clicks = 0; + }, tracker.dblClickTimeThreshold ); + /*jshint loopfunc:false*/ + } else if ( pointsList.clicks === 2 ) { + clearTimeout( delegate.dblClickTimeOut ); + pointsList.clicks = 0; + if ( delegate.lastClickPos.distanceTo( releasePoint ) <= tracker.dblClickDistThreshold ) { + propagate = tracker.dblClickHandler( + { + eventSource: tracker, + pointerType: updateGPoint.type, + position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ), + shift: event.shiftKey, + isTouchEvent: updateGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + delegate.lastClickPos = null; + } + } + } + } else if ( pointsList.contacts === 2 ) { + if ( tracker.pinchHandler && updateGPoint.type === 'touch' ) { + // Reset for pinch + delegate.pinchGPoints = pointsList.asArray(); + delegate.lastPinchDist = delegate.currentPinchDist = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos ); + delegate.lastPinchCenter = delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos ); + } + } + } else { + // Pointer was activated in another element but removed in our element + + // Release (pressed in another element) + if ( tracker.releaseHandler ) { + propagate = tracker.releaseHandler( + { + eventSource: tracker, + pointerType: updateGPoint.type, + position: getPointRelativeToAbsolute( releasePoint, tracker.element ), + buttons: pointsList.buttons, + insideElementPressed: updateGPoint.insideElementPressed, + insideElementReleased: updateGPoint.insideElement, + isTouchEvent: updateGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } + } + } + + return releaseCapture; + } + + + /** + * Call when pointer(s) change coordinates, button state, pressure, tilt, or contact geometry (e.g. width and height) + * + * @function + * @private + * @inner + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the MouseTracker instance. + * @param {Object} event + * A reference to the originating DOM event. + * @param {Array.} gPoints + * Gesture points associated with the event. + */ + function updatePointersMove( tracker, event, gPoints ) { + var delegate = THIS[ tracker.hash ], + pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ), + i, + gPointCount = gPoints.length, + curGPoint, + updateGPoint, + gPointArray, + delta, + propagate; + + if ( typeof event.buttons !== 'undefined' ) { + pointsList.buttons = event.buttons; + } + + for ( i = 0; i < gPointCount; i++ ) { + curGPoint = gPoints[ i ]; + updateGPoint = pointsList.getById( curGPoint.id ); + + if ( updateGPoint ) { + // Already tracking the pointer...update it + if ( curGPoint.hasOwnProperty( 'isPrimary' ) ) { + updateGPoint.isPrimary = curGPoint.isPrimary; + } + updateGPoint.lastPos = updateGPoint.currentPos; + updateGPoint.lastTime = updateGPoint.currentTime; + updateGPoint.currentPos = curGPoint.currentPos; + updateGPoint.currentTime = curGPoint.currentTime; + } else { + // Initialize for tracking and add to the tracking list (no pointerover or pointerdown event occurred before this) + curGPoint.captured = false; + curGPoint.insideElementPressed = false; + curGPoint.insideElement = true; + startTrackingPointer( pointsList, curGPoint ); + } + } + + // Stop (mouse only) + if ( tracker.stopHandler && gPoints[ 0 ].type === 'mouse' ) { + clearTimeout( tracker.stopTimeOut ); + tracker.stopTimeOut = setTimeout( function() { + handlePointerStop( tracker, event, gPoints[ 0 ].type ); + }, tracker.stopDelay ); + } + + if ( pointsList.contacts === 0 ) { + // Move (no contacts: hovering mouse or other hover-capable device) + if ( tracker.moveHandler ) { + propagate = tracker.moveHandler( + { + eventSource: tracker, + pointerType: gPoints[ 0 ].type, + position: getPointRelativeToAbsolute( gPoints[ 0 ].currentPos, tracker.element ), + buttons: pointsList.buttons, + isTouchEvent: gPoints[ 0 ].type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } else if ( pointsList.contacts === 1 ) { + // Move (1 contact) + if ( tracker.moveHandler ) { + updateGPoint = pointsList.asArray()[ 0 ]; + propagate = tracker.moveHandler( + { + eventSource: tracker, + pointerType: updateGPoint.type, + position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ), + buttons: pointsList.buttons, + isTouchEvent: updateGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + + // Drag + if ( tracker.dragHandler ) { + updateGPoint = pointsList.asArray()[ 0 ]; + delta = updateGPoint.currentPos.minus( updateGPoint.lastPos ); + propagate = tracker.dragHandler( + { + eventSource: tracker, + pointerType: updateGPoint.type, + position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ), + buttons: pointsList.buttons, + delta: delta, + speed: updateGPoint.speed, + direction: updateGPoint.direction, + shift: event.shiftKey, + isTouchEvent: updateGPoint.type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } else if ( pointsList.contacts === 2 ) { + // Move (2 contacts, use center) + if ( tracker.moveHandler ) { + gPointArray = pointsList.asArray(); + propagate = tracker.moveHandler( + { + eventSource: tracker, + pointerType: gPointArray[ 0 ].type, + position: getPointRelativeToAbsolute( getCenterPoint( gPointArray[ 0 ].currentPos, gPointArray[ 1 ].currentPos ), tracker.element ), + buttons: pointsList.buttons, + isTouchEvent: gPointArray[ 0 ].type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + + // Pinch + if ( tracker.pinchHandler && gPoints[ 0 ].type === 'touch' ) { + delta = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos ); + if ( delta != delegate.currentPinchDist ) { + delegate.lastPinchDist = delegate.currentPinchDist; + delegate.currentPinchDist = delta; + delegate.lastPinchCenter = delegate.currentPinchCenter; + delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos ); + propagate = tracker.pinchHandler( + { + eventSource: tracker, + pointerType: 'touch', + gesturePoints: delegate.pinchGPoints, + lastCenter: getPointRelativeToAbsolute( delegate.lastPinchCenter, tracker.element ), + center: getPointRelativeToAbsolute( delegate.currentPinchCenter, tracker.element ), + lastDistance: delegate.lastPinchDist, + distance: delegate.currentPinchDist, + shift: event.shiftKey, + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + } + } + } + + + /** + * @function + * @private + * @inner + * @param {OpenSeadragon.MouseTracker} tracker + * A reference to the MouseTracker instance. + * @param {Object} event + * A reference to the originating DOM event. + * @param {Array.} gPoints + * Gesture points associated with the event. + */ + function updatePointersCancel( tracker, event, gPoints ) { + updatePointersUp( tracker, event, gPoints, 0 ); + updatePointersExit( tracker, event, gPoints ); + } + + + /** + * @private + * @inner + */ + function handlePointerStop( tracker, originalMoveEvent, pointerType ) { + if ( tracker.stopHandler ) { + tracker.stopHandler( { + eventSource: tracker, + pointerType: pointerType, + position: getMouseRelative( originalMoveEvent, tracker.element ), + buttons: tracker.getActivePointersListByType( pointerType ).buttons, + isTouchEvent: pointerType === 'touch', + originalEvent: originalMoveEvent, + preventDefaultAction: false, + userData: tracker.userData + } ); + } + } + + /** + * True if inside an iframe, otherwise false. + * @member {Boolean} isInIframe + * @private + * @inner + */ + var isInIframe = (function() { + try { + return window.self !== window.top; + } catch (e) { + return true; + } + })(); + + /** + * @function + * @private + * @inner + * @returns {Boolean} True if the target has access rights to events, otherwise false. + */ + function canAccessEvents (target) { + try { + return target.addEventListener && target.removeEventListener; + } catch (e) { + return false; + } + } + +}(OpenSeadragon)); + +/* + * OpenSeadragon - Control + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * An enumeration of supported locations where controls can be anchored. + * The anchoring is always relative to the container. + * @member ControlAnchor + * @memberof OpenSeadragon + * @static + * @type {Object} + * @property {Number} NONE + * @property {Number} TOP_LEFT + * @property {Number} TOP_RIGHT + * @property {Number} BOTTOM_LEFT + * @property {Number} BOTTOM_RIGHT + * @property {Number} ABSOLUTE + */ +$.ControlAnchor = { + NONE: 0, + TOP_LEFT: 1, + TOP_RIGHT: 2, + BOTTOM_RIGHT: 3, + BOTTOM_LEFT: 4, + ABSOLUTE: 5 +}; + +/** + * @class Control + * @classdesc A Control represents any interface element which is meant to allow the user + * to interact with the zoomable interface. Any control can be anchored to any + * element. + * + * @memberof OpenSeadragon + * @param {Element} element - the control element to be anchored in the container. + * @param {Object } options - All required and optional settings for configuring a control element. + * @param {OpenSeadragon.ControlAnchor} [options.anchor=OpenSeadragon.ControlAnchor.NONE] - the position of the control + * relative to the container. + * @param {Boolean} [options.attachToViewer=true] - Whether the control should be added directly to the viewer, or + * directly to the container + * @param {Boolean} [options.autoFade=true] - Whether the control should have the autofade behavior + * @param {Element} container - the element to control will be anchored too. + */ +$.Control = function ( element, options, container ) { + var parent = element.parentNode; + if (typeof options === 'number') + { + $.console.error("Passing an anchor directly into the OpenSeadragon.Control constructor is deprecated; " + + "please use an options object instead. " + + "Support for this deprecated variant is scheduled for removal in December 2013"); + options = {anchor: options}; + } + options.attachToViewer = (typeof options.attachToViewer === 'undefined') ? true : options.attachToViewer; + /** + * True if the control should have autofade behavior. + * @member {Boolean} autoFade + * @memberof OpenSeadragon.Control# + */ + this.autoFade = (typeof options.autoFade === 'undefined') ? true : options.autoFade; + /** + * The element providing the user interface with some type of control (e.g. a zoom-in button). + * @member {Element} element + * @memberof OpenSeadragon.Control# + */ + this.element = element; + /** + * The position of the Control relative to its container. + * @member {OpenSeadragon.ControlAnchor} anchor + * @memberof OpenSeadragon.Control# + */ + this.anchor = options.anchor; + /** + * The Control's containing element. + * @member {Element} container + * @memberof OpenSeadragon.Control# + */ + this.container = container; + /** + * A neutral element surrounding the control element. + * @member {Element} wrapper + * @memberof OpenSeadragon.Control# + */ + if ( this.anchor == $.ControlAnchor.ABSOLUTE ) { + this.wrapper = $.makeNeutralElement( "div" ); + this.wrapper.style.position = "absolute"; + this.wrapper.style.top = typeof (options.top) == "number" ? (options.top + 'px') : options.top; + this.wrapper.style.left = typeof (options.left) == "number" ? (options.left + 'px') : options.left; + this.wrapper.style.height = typeof (options.height) == "number" ? (options.height + 'px') : options.height; + this.wrapper.style.width = typeof (options.width) == "number" ? (options.width + 'px') : options.width; + this.wrapper.style.margin = "0px"; + this.wrapper.style.padding = "0px"; + + this.element.style.position = "relative"; + this.element.style.top = "0px"; + this.element.style.left = "0px"; + this.element.style.height = "100%"; + this.element.style.width = "100%"; + } else { + this.wrapper = $.makeNeutralElement( "div" ); + this.wrapper.style.display = "inline-block"; + if ( this.anchor == $.ControlAnchor.NONE ) { + // IE6 fix + this.wrapper.style.width = this.wrapper.style.height = "100%"; + } + } + this.wrapper.appendChild( this.element ); + + if (options.attachToViewer ) { + if ( this.anchor == $.ControlAnchor.TOP_RIGHT || + this.anchor == $.ControlAnchor.BOTTOM_RIGHT ) { + this.container.insertBefore( + this.wrapper, + this.container.firstChild + ); + } else { + this.container.appendChild( this.wrapper ); + } + } else { + parent.appendChild( this.wrapper ); + } +}; + +/** @lends OpenSeadragon.Control.prototype */ +$.Control.prototype = { + + /** + * Removes the control from the container. + * @function + */ + destroy: function() { + this.wrapper.removeChild( this.element ); + this.container.removeChild( this.wrapper ); + }, + + /** + * Determines if the control is currently visible. + * @function + * @return {Boolean} true if currenly visible, false otherwise. + */ + isVisible: function() { + return this.wrapper.style.display != "none"; + }, + + /** + * Toggles the visibility of the control. + * @function + * @param {Boolean} visible - true to make visible, false to hide. + */ + setVisible: function( visible ) { + this.wrapper.style.display = visible ? + ( this.anchor == $.ControlAnchor.ABSOLUTE ? 'block' : 'inline-block' ) : + "none"; + }, + + /** + * Sets the opacity level for the control. + * @function + * @param {Number} opactiy - a value between 1 and 0 inclusively. + */ + setOpacity: function( opacity ) { + if ( this.element[ $.SIGNAL ] && $.Browser.vendor == $.BROWSERS.IE ) { + $.setElementOpacity( this.element, opacity, true ); + } else { + $.setElementOpacity( this.wrapper, opacity, true ); + } + } +}; + +}( OpenSeadragon )); + +/* + * OpenSeadragon - ControlDock + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + /** + * @class ControlDock + * @classdesc Provides a container element (a <form> element) with support for the layout of control elements. + * + * @memberof OpenSeadragon + */ + $.ControlDock = function( options ){ + var layouts = [ 'topleft', 'topright', 'bottomright', 'bottomleft'], + layout, + i; + + $.extend( true, this, { + id: 'controldock-' + $.now() + '-' + Math.floor(Math.random() * 1000000), + container: $.makeNeutralElement( 'div' ), + controls: [] + }, options ); + + // Disable the form's submit; otherwise button clicks and return keys + // can trigger it. + this.container.onsubmit = function() { + return false; + }; + + if( this.element ){ + this.element = $.getElement( this.element ); + this.element.appendChild( this.container ); + this.element.style.position = 'relative'; + this.container.style.width = '100%'; + this.container.style.height = '100%'; + } + + for( i = 0; i < layouts.length; i++ ){ + layout = layouts[ i ]; + this.controls[ layout ] = $.makeNeutralElement( "div" ); + this.controls[ layout ].style.position = 'absolute'; + if ( layout.match( 'left' ) ){ + this.controls[ layout ].style.left = '0px'; + } + if ( layout.match( 'right' ) ){ + this.controls[ layout ].style.right = '0px'; + } + if ( layout.match( 'top' ) ){ + this.controls[ layout ].style.top = '0px'; + } + if ( layout.match( 'bottom' ) ){ + this.controls[ layout ].style.bottom = '0px'; + } + } + + this.container.appendChild( this.controls.topleft ); + this.container.appendChild( this.controls.topright ); + this.container.appendChild( this.controls.bottomright ); + this.container.appendChild( this.controls.bottomleft ); + }; + + /** @lends OpenSeadragon.ControlDock.prototype */ + $.ControlDock.prototype = { + + /** + * @function + */ + addControl: function ( element, controlOptions ) { + element = $.getElement( element ); + var div = null; + + if ( getControlIndex( this, element ) >= 0 ) { + return; // they're trying to add a duplicate control + } + + switch ( controlOptions.anchor ) { + case $.ControlAnchor.TOP_RIGHT: + div = this.controls.topright; + element.style.position = "relative"; + element.style.paddingRight = "0px"; + element.style.paddingTop = "0px"; + break; + case $.ControlAnchor.BOTTOM_RIGHT: + div = this.controls.bottomright; + element.style.position = "relative"; + element.style.paddingRight = "0px"; + element.style.paddingBottom = "0px"; + break; + case $.ControlAnchor.BOTTOM_LEFT: + div = this.controls.bottomleft; + element.style.position = "relative"; + element.style.paddingLeft = "0px"; + element.style.paddingBottom = "0px"; + break; + case $.ControlAnchor.TOP_LEFT: + div = this.controls.topleft; + element.style.position = "relative"; + element.style.paddingLeft = "0px"; + element.style.paddingTop = "0px"; + break; + case $.ControlAnchor.ABSOLUTE: + div = this.container; + element.style.margin = "0px"; + element.style.padding = "0px"; + break; + default: + case $.ControlAnchor.NONE: + div = this.container; + element.style.margin = "0px"; + element.style.padding = "0px"; + break; + } + + this.controls.push( + new $.Control( element, controlOptions, div ) + ); + element.style.display = "inline-block"; + }, + + + /** + * @function + * @return {OpenSeadragon.ControlDock} Chainable. + */ + removeControl: function ( element ) { + element = $.getElement( element ); + var i = getControlIndex( this, element ); + + if ( i >= 0 ) { + this.controls[ i ].destroy(); + this.controls.splice( i, 1 ); + } + + return this; + }, + + /** + * @function + * @return {OpenSeadragon.ControlDock} Chainable. + */ + clearControls: function () { + while ( this.controls.length > 0 ) { + this.controls.pop().destroy(); + } + + return this; + }, + + + /** + * @function + * @return {Boolean} + */ + areControlsEnabled: function () { + var i; + + for ( i = this.controls.length - 1; i >= 0; i-- ) { + if ( this.controls[ i ].isVisible() ) { + return true; + } + } + + return false; + }, + + + /** + * @function + * @return {OpenSeadragon.ControlDock} Chainable. + */ + setControlsEnabled: function( enabled ) { + var i; + + for ( i = this.controls.length - 1; i >= 0; i-- ) { + this.controls[ i ].setVisible( enabled ); + } + + return this; + } + + }; + + + /////////////////////////////////////////////////////////////////////////////// + // Utility methods + /////////////////////////////////////////////////////////////////////////////// + function getControlIndex( dock, element ) { + var controls = dock.controls, + i; + + for ( i = controls.length - 1; i >= 0; i-- ) { + if ( controls[ i ].element == element ) { + return i; + } + } + + return -1; + } + +}( OpenSeadragon )); + +/* + * OpenSeadragon - Placement + * + * Copyright (C) 2010-2016 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function($) { + + /** + * An enumeration of positions to anchor an element. + * @member Placement + * @memberOf OpenSeadragon + * @static + * @readonly + * @property {OpenSeadragon.Placement} CENTER + * @property {OpenSeadragon.Placement} TOP_LEFT + * @property {OpenSeadragon.Placement} TOP + * @property {OpenSeadragon.Placement} TOP_RIGHT + * @property {OpenSeadragon.Placement} RIGHT + * @property {OpenSeadragon.Placement} BOTTOM_RIGHT + * @property {OpenSeadragon.Placement} BOTTOM + * @property {OpenSeadragon.Placement} BOTTOM_LEFT + * @property {OpenSeadragon.Placement} LEFT + */ + $.Placement = $.freezeObject({ + CENTER: 0, + TOP_LEFT: 1, + TOP: 2, + TOP_RIGHT: 3, + RIGHT: 4, + BOTTOM_RIGHT: 5, + BOTTOM: 6, + BOTTOM_LEFT: 7, + LEFT: 8, + properties: { + 0: { + isLeft: false, + isHorizontallyCentered: true, + isRight: false, + isTop: false, + isVerticallyCentered: true, + isBottom: false + }, + 1: { + isLeft: true, + isHorizontallyCentered: false, + isRight: false, + isTop: true, + isVerticallyCentered: false, + isBottom: false + }, + 2: { + isLeft: false, + isHorizontallyCentered: true, + isRight: false, + isTop: true, + isVerticallyCentered: false, + isBottom: false + }, + 3: { + isLeft: false, + isHorizontallyCentered: false, + isRight: true, + isTop: true, + isVerticallyCentered: false, + isBottom: false + }, + 4: { + isLeft: false, + isHorizontallyCentered: false, + isRight: true, + isTop: false, + isVerticallyCentered: true, + isBottom: false + }, + 5: { + isLeft: false, + isHorizontallyCentered: false, + isRight: true, + isTop: false, + isVerticallyCentered: false, + isBottom: true + }, + 6: { + isLeft: false, + isHorizontallyCentered: true, + isRight: false, + isTop: false, + isVerticallyCentered: false, + isBottom: true + }, + 7: { + isLeft: true, + isHorizontallyCentered: false, + isRight: false, + isTop: false, + isVerticallyCentered: false, + isBottom: true + }, + 8: { + isLeft: true, + isHorizontallyCentered: false, + isRight: false, + isTop: false, + isVerticallyCentered: true, + isBottom: false + } + } + }); + +}(OpenSeadragon)); + +/* + * OpenSeadragon - Viewer + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +// dictionary from hash to private properties +var THIS = {}; +var nextHash = 1; + +/** + * + * The main point of entry into creating a zoomable image on the page.
      + *
      + * We have provided an idiomatic javascript constructor which takes + * a single object, but still support the legacy positional arguments.
      + *
      + * The options below are given in order that they appeared in the constructor + * as arguments and we translate a positional call into an idiomatic call.
      + *
      + * To create a viewer, you can use either of this methods:
      + *
        + *
      • var viewer = new OpenSeadragon.Viewer(options);
      • + *
      • var viewer = OpenSeadragon(options);
      • + *
      + * @class Viewer + * @classdesc The main OpenSeadragon viewer class. + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.EventSource + * @extends OpenSeadragon.ControlDock + * @param {OpenSeadragon.Options} options - Viewer options. + * + **/ +$.Viewer = function( options ) { + + var args = arguments, + _this = this, + i; + + + //backward compatibility for positional args while prefering more + //idiomatic javascript options object as the only argument + if( !$.isPlainObject( options ) ){ + options = { + id: args[ 0 ], + xmlPath: args.length > 1 ? args[ 1 ] : undefined, + prefixUrl: args.length > 2 ? args[ 2 ] : undefined, + controls: args.length > 3 ? args[ 3 ] : undefined, + overlays: args.length > 4 ? args[ 4 ] : undefined + }; + } + + //options.config and the general config argument are deprecated + //in favor of the more direct specification of optional settings + //being pass directly on the options object + if ( options.config ){ + $.extend( true, options, options.config ); + delete options.config; + } + + //Public properties + //Allow the options object to override global defaults + $.extend( true, this, { + + //internal state and dom identifiers + id: options.id, + hash: options.hash || nextHash++, + /** + * Index for page to be shown first next time open() is called (only used in sequenceMode). + * @member {Number} initialPage + * @memberof OpenSeadragon.Viewer# + */ + initialPage: 0, + + //dom nodes + /** + * The parent element of this Viewer instance, passed in when the Viewer was created. + * @member {Element} element + * @memberof OpenSeadragon.Viewer# + */ + element: null, + /** + * A <div> element (provided by {@link OpenSeadragon.ControlDock}), the base element of this Viewer instance.

      + * Child element of {@link OpenSeadragon.Viewer#element}. + * @member {Element} container + * @memberof OpenSeadragon.Viewer# + */ + container: null, + /** + * A <div> element, the element where user-input events are handled for panning and zooming.

      + * Child element of {@link OpenSeadragon.Viewer#container}, + * positioned on top of {@link OpenSeadragon.Viewer#keyboardCommandArea}.

      + * The parent of {@link OpenSeadragon.Drawer#canvas} instances. + * @member {Element} canvas + * @memberof OpenSeadragon.Viewer# + */ + canvas: null, + + // Overlays list. An overlay allows to add html on top of the viewer. + overlays: [], + // Container inside the canvas where overlays are drawn. + overlaysContainer: null, + + //private state properties + previousBody: [], + + //This was originally initialized in the constructor and so could never + //have anything in it. now it can because we allow it to be specified + //in the options and is only empty by default if not specified. Also + //this array was returned from get_controls which I find confusing + //since this object has a controls property which is treated in other + //functions like clearControls. I'm removing the accessors. + customControls: [], + + //These are originally not part options but declared as members + //in initialize. It's still considered idiomatic to put them here + source: null, + /** + * Handles rendering of tiles in the viewer. Created for each TileSource opened. + * @member {OpenSeadragon.Drawer} drawer + * @memberof OpenSeadragon.Viewer# + */ + drawer: null, + world: null, + /** + * Handles coordinate-related functionality - zoom, pan, rotation, etc. Created for each TileSource opened. + * @member {OpenSeadragon.Viewport} viewport + * @memberof OpenSeadragon.Viewer# + */ + viewport: null, + /** + * @member {OpenSeadragon.Navigator} navigator + * @memberof OpenSeadragon.Viewer# + */ + navigator: null, + + //A collection viewport is a separate viewport used to provide + //simultaneous rendering of sets of tiles + collectionViewport: null, + collectionDrawer: null, + + //UI image resources + //TODO: rename navImages to uiImages + navImages: null, + + //interface button controls + buttons: null, + + //TODO: this is defunct so safely remove it + profiler: null + + }, $.DEFAULT_SETTINGS, options ); + + if ( typeof( this.hash) === "undefined" ) { + throw new Error("A hash must be defined, either by specifying options.id or options.hash."); + } + if ( typeof( THIS[ this.hash ] ) !== "undefined" ) { + // We don't want to throw an error here, as the user might have discarded + // the previous viewer with the same hash and now want to recreate it. + $.console.warn("Hash " + this.hash + " has already been used."); + } + + //Private state properties + THIS[ this.hash ] = { + "fsBoundsDelta": new $.Point( 1, 1 ), + "prevContainerSize": null, + "animating": false, + "forceRedraw": false, + "mouseInside": false, + "group": null, + // whether we should be continuously zooming + "zooming": false, + // how much we should be continuously zooming by + "zoomFactor": null, + "lastZoomTime": null, + "fullPage": false, + "onfullscreenchange": null + }; + + this._sequenceIndex = 0; + this._firstOpen = true; + this._updateRequestId = null; + this._loadQueue = []; + this.currentOverlays = []; + + this._lastScrollTime = $.now(); // variable used to help normalize the scroll event speed of different devices + + //Inherit some behaviors and properties + $.EventSource.call( this ); + + this.addHandler( 'open-failed', function ( event ) { + var msg = $.getString( "Errors.OpenFailed", event.eventSource, event.message); + _this._showMessage( msg ); + }); + + $.ControlDock.call( this, options ); + + //Deal with tile sources + if (this.xmlPath) { + //Deprecated option. Now it is preferred to use the tileSources option + this.tileSources = [ this.xmlPath ]; + } + + this.element = this.element || document.getElementById( this.id ); + this.canvas = $.makeNeutralElement( "div" ); + + this.canvas.className = "openseadragon-canvas"; + (function( style ){ + style.width = "100%"; + style.height = "100%"; + style.overflow = "hidden"; + style.position = "absolute"; + style.top = "0px"; + style.left = "0px"; + }(this.canvas.style)); + $.setElementTouchActionNone( this.canvas ); + if (options.tabIndex !== "") { + this.canvas.tabIndex = (options.tabIndex === undefined ? 0 : options.tabIndex); + } + + //the container is created through applying the ControlDock constructor above + this.container.className = "openseadragon-container"; + (function( style ){ + style.width = "100%"; + style.height = "100%"; + style.position = "relative"; + style.overflow = "hidden"; + style.left = "0px"; + style.top = "0px"; + style.textAlign = "left"; // needed to protect against + }( this.container.style )); + + this.container.insertBefore( this.canvas, this.container.firstChild ); + this.element.appendChild( this.container ); + + //Used for toggling between fullscreen and default container size + //TODO: these can be closure private and shared across Viewer + // instances. + this.bodyWidth = document.body.style.width; + this.bodyHeight = document.body.style.height; + this.bodyOverflow = document.body.style.overflow; + this.docOverflow = document.documentElement.style.overflow; + + this.innerTracker = new $.MouseTracker({ + element: this.canvas, + startDisabled: !this.mouseNavEnabled, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + dblClickTimeThreshold: this.dblClickTimeThreshold, + dblClickDistThreshold: this.dblClickDistThreshold, + keyDownHandler: $.delegate( this, onCanvasKeyDown ), + keyHandler: $.delegate( this, onCanvasKeyPress ), + clickHandler: $.delegate( this, onCanvasClick ), + dblClickHandler: $.delegate( this, onCanvasDblClick ), + dragHandler: $.delegate( this, onCanvasDrag ), + dragEndHandler: $.delegate( this, onCanvasDragEnd ), + enterHandler: $.delegate( this, onCanvasEnter ), + exitHandler: $.delegate( this, onCanvasExit ), + pressHandler: $.delegate( this, onCanvasPress ), + releaseHandler: $.delegate( this, onCanvasRelease ), + nonPrimaryPressHandler: $.delegate( this, onCanvasNonPrimaryPress ), + nonPrimaryReleaseHandler: $.delegate( this, onCanvasNonPrimaryRelease ), + scrollHandler: $.delegate( this, onCanvasScroll ), + pinchHandler: $.delegate( this, onCanvasPinch ) + }); + + this.outerTracker = new $.MouseTracker({ + element: this.container, + startDisabled: !this.mouseNavEnabled, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + dblClickTimeThreshold: this.dblClickTimeThreshold, + dblClickDistThreshold: this.dblClickDistThreshold, + enterHandler: $.delegate( this, onContainerEnter ), + exitHandler: $.delegate( this, onContainerExit ) + }); + + if( this.toolbar ){ + this.toolbar = new $.ControlDock({ element: this.toolbar }); + } + + this.bindStandardControls(); + + THIS[ this.hash ].prevContainerSize = _getSafeElemSize( this.container ); + + // Create the world + this.world = new $.World({ + viewer: this + }); + + this.world.addHandler('add-item', function(event) { + // For backwards compatibility, we maintain the source property + _this.source = _this.world.getItemAt(0).source; + + THIS[ _this.hash ].forceRedraw = true; + + if (!_this._updateRequestId) { + _this._updateRequestId = scheduleUpdate( _this, updateMulti ); + } + }); + + this.world.addHandler('remove-item', function(event) { + // For backwards compatibility, we maintain the source property + if (_this.world.getItemCount()) { + _this.source = _this.world.getItemAt(0).source; + } else { + _this.source = null; + } + + THIS[ _this.hash ].forceRedraw = true; + }); + + this.world.addHandler('metrics-change', function(event) { + if (_this.viewport) { + _this.viewport._setContentBounds(_this.world.getHomeBounds(), _this.world.getContentFactor()); + } + }); + + this.world.addHandler('item-index-change', function(event) { + // For backwards compatibility, we maintain the source property + _this.source = _this.world.getItemAt(0).source; + }); + + // Create the viewport + this.viewport = new $.Viewport({ + containerSize: THIS[ this.hash ].prevContainerSize, + springStiffness: this.springStiffness, + animationTime: this.animationTime, + minZoomImageRatio: this.minZoomImageRatio, + maxZoomPixelRatio: this.maxZoomPixelRatio, + visibilityRatio: this.visibilityRatio, + wrapHorizontal: this.wrapHorizontal, + wrapVertical: this.wrapVertical, + defaultZoomLevel: this.defaultZoomLevel, + minZoomLevel: this.minZoomLevel, + maxZoomLevel: this.maxZoomLevel, + viewer: this, + degrees: this.degrees, + navigatorRotate: this.navigatorRotate, + homeFillsViewer: this.homeFillsViewer, + margins: this.viewportMargins + }); + + this.viewport._setContentBounds(this.world.getHomeBounds(), this.world.getContentFactor()); + + // Create the image loader + this.imageLoader = new $.ImageLoader({ + jobLimit: this.imageLoaderLimit, + timeout: options.timeout + }); + + // Create the tile cache + this.tileCache = new $.TileCache({ + maxImageCacheCount: this.maxImageCacheCount + }); + + // Create the drawer + this.drawer = new $.Drawer({ + viewer: this, + viewport: this.viewport, + element: this.canvas, + debugGridColor: this.debugGridColor + }); + + // Overlay container + this.overlaysContainer = $.makeNeutralElement( "div" ); + this.canvas.appendChild( this.overlaysContainer ); + + // Now that we have a drawer, see if it supports rotate. If not we need to remove the rotate buttons + if (!this.drawer.canRotate()) { + // Disable/remove the rotate left/right buttons since they aren't supported + if (this.rotateLeft) { + i = this.buttons.buttons.indexOf(this.rotateLeft); + this.buttons.buttons.splice(i, 1); + this.buttons.element.removeChild(this.rotateLeft.element); + } + if (this.rotateRight) { + i = this.buttons.buttons.indexOf(this.rotateRight); + this.buttons.buttons.splice(i, 1); + this.buttons.element.removeChild(this.rotateRight.element); + } + } + + //Instantiate a navigator if configured + if ( this.showNavigator){ + this.navigator = new $.Navigator({ + id: this.navigatorId, + position: this.navigatorPosition, + sizeRatio: this.navigatorSizeRatio, + maintainSizeRatio: this.navigatorMaintainSizeRatio, + top: this.navigatorTop, + left: this.navigatorLeft, + width: this.navigatorWidth, + height: this.navigatorHeight, + autoResize: this.navigatorAutoResize, + autoFade: this.navigatorAutoFade, + prefixUrl: this.prefixUrl, + viewer: this, + navigatorRotate: this.navigatorRotate, + crossOriginPolicy: this.crossOriginPolicy + }); + } + + // Sequence mode + if (this.sequenceMode) { + this.bindSequenceControls(); + } + + // Open initial tilesources + if (this.tileSources) { + this.open( this.tileSources ); + } + + // Add custom controls + for ( i = 0; i < this.customControls.length; i++ ) { + this.addControl( + this.customControls[ i ].id, + {anchor: this.customControls[ i ].anchor} + ); + } + + // Initial fade out + $.requestAnimationFrame( function(){ + beginControlsAutoHide( _this ); + } ); +}; + +$.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, /** @lends OpenSeadragon.Viewer.prototype */{ + + + /** + * @function + * @return {Boolean} + */ + isOpen: function () { + return !!this.world.getItemCount(); + }, + + // deprecated + openDzi: function ( dzi ) { + $.console.error( "[Viewer.openDzi] this function is deprecated; use Viewer.open() instead." ); + return this.open( dzi ); + }, + + // deprecated + openTileSource: function ( tileSource ) { + $.console.error( "[Viewer.openTileSource] this function is deprecated; use Viewer.open() instead." ); + return this.open( tileSource ); + }, + + /** + * Open tiled images into the viewer, closing any others. + * @function + * @param {Array|String|Object|Function} tileSources - This can be a TiledImage + * specifier, a TileSource specifier, or an array of either. A TiledImage specifier + * is the same as the options parameter for {@link OpenSeadragon.Viewer#addTiledImage}, + * except for the index property; images are added in sequence. + * A TileSource specifier is anything you could pass as the tileSource property + * of the options parameter for {@link OpenSeadragon.Viewer#addTiledImage}. + * @param {Number} initialPage - If sequenceMode is true, display this page initially + * for the given tileSources. If specified, will overwrite the Viewer's existing initialPage property. + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:open + * @fires OpenSeadragon.Viewer.event:open-failed + */ + open: function (tileSources, initialPage) { + var _this = this; + + this.close(); + + if (!tileSources) { + return; + } + + if (this.sequenceMode && $.isArray(tileSources)) { + if (this.referenceStrip) { + this.referenceStrip.destroy(); + this.referenceStrip = null; + } + + if (typeof initialPage != 'undefined' && !isNaN(initialPage)) { + this.initialPage = initialPage; + } + + this.tileSources = tileSources; + this._sequenceIndex = Math.max(0, Math.min(this.tileSources.length - 1, this.initialPage)); + if (this.tileSources.length) { + this.open(this.tileSources[this._sequenceIndex]); + + if ( this.showReferenceStrip ){ + this.addReferenceStrip(); + } + } + + this._updateSequenceButtons( this._sequenceIndex ); + return; + } + + if (!$.isArray(tileSources)) { + tileSources = [tileSources]; + } + + if (!tileSources.length) { + return; + } + + this._opening = true; + + var expected = tileSources.length; + var successes = 0; + var failures = 0; + var failEvent; + + var checkCompletion = function() { + if (successes + failures === expected) { + if (successes) { + if (_this._firstOpen || !_this.preserveViewport) { + _this.viewport.goHome( true ); + _this.viewport.update(); + } + + _this._firstOpen = false; + + var source = tileSources[0]; + if (source.tileSource) { + source = source.tileSource; + } + + // Global overlays + if( _this.overlays && !_this.preserveOverlays ){ + for ( var i = 0; i < _this.overlays.length; i++ ) { + _this.currentOverlays[ i ] = getOverlayObject( _this, _this.overlays[ i ] ); + } + } + + _this._drawOverlays(); + _this._opening = false; + + /** + * Raised when the viewer has opened and loaded one or more TileSources. + * + * @event open + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {OpenSeadragon.TileSource} source - The tile source that was opened. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + // TODO: what if there are multiple sources? + _this.raiseEvent( 'open', { source: source } ); + } else { + _this._opening = false; + + /** + * Raised when an error occurs loading a TileSource. + * + * @event open-failed + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {String} message - Information about what failed. + * @property {String} source - The tile source that failed. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( 'open-failed', failEvent ); + } + } + }; + + var doOne = function(options) { + if (!$.isPlainObject(options) || !options.tileSource) { + options = { + tileSource: options + }; + } + + if (options.index !== undefined) { + $.console.error('[Viewer.open] setting indexes here is not supported; use addTiledImage instead'); + delete options.index; + } + + if (options.collectionImmediately === undefined) { + options.collectionImmediately = true; + } + + var originalSuccess = options.success; + options.success = function(event) { + successes++; + + // TODO: now that options has other things besides tileSource, the overlays + // should probably be at the options level, not the tileSource level. + if (options.tileSource.overlays) { + for (var i = 0; i < options.tileSource.overlays.length; i++) { + _this.addOverlay(options.tileSource.overlays[i]); + } + } + + if (originalSuccess) { + originalSuccess(event); + } + + checkCompletion(); + }; + + var originalError = options.error; + options.error = function(event) { + failures++; + + if (!failEvent) { + failEvent = event; + } + + if (originalError) { + originalError(event); + } + + checkCompletion(); + }; + + _this.addTiledImage(options); + }; + + // TileSources + for (var i = 0; i < tileSources.length; i++) { + doOne(tileSources[i]); + } + + return this; + }, + + + /** + * @function + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:close + */ + close: function ( ) { + if ( !THIS[ this.hash ] ) { + //this viewer has already been destroyed: returning immediately + return this; + } + + this._opening = false; + + if ( this.navigator ) { + this.navigator.close(); + } + + if (!this.preserveOverlays) { + this.clearOverlays(); + this.overlaysContainer.innerHTML = ""; + } + + THIS[ this.hash ].animating = false; + this.world.removeAll(); + this.imageLoader.clear(); + + /** + * Raised when the viewer is closed (see {@link OpenSeadragon.Viewer#close}). + * + * @event close + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'close' ); + + return this; + }, + + + /** + * Function to destroy the viewer and clean up everything created by OpenSeadragon. + * + * Example: + * var viewer = OpenSeadragon({ + * [...] + * }); + * + * //when you are done with the viewer: + * viewer.destroy(); + * viewer = null; //important + * + * @function + */ + destroy: function( ) { + if ( !THIS[ this.hash ] ) { + //this viewer has already been destroyed: returning immediately + return; + } + + this.close(); + + this.clearOverlays(); + this.overlaysContainer.innerHTML = ""; + + //TODO: implement this... + //this.unbindSequenceControls() + //this.unbindStandardControls() + + if (this.referenceStrip) { + this.referenceStrip.destroy(); + this.referenceStrip = null; + } + + if ( this._updateRequestId !== null ) { + $.cancelAnimationFrame( this._updateRequestId ); + this._updateRequestId = null; + } + + if ( this.drawer ) { + this.drawer.destroy(); + } + + this.removeAllHandlers(); + + // Go through top element (passed to us) and remove all children + // Use removeChild to make sure it handles SVG or any non-html + // also it performs better - http://jsperf.com/innerhtml-vs-removechild/15 + if (this.element){ + while (this.element.firstChild) { + this.element.removeChild(this.element.firstChild); + } + } + + // destroy the mouse trackers + if (this.innerTracker){ + this.innerTracker.destroy(); + } + if (this.outerTracker){ + this.outerTracker.destroy(); + } + + THIS[ this.hash ] = null; + delete THIS[ this.hash ]; + + // clear all our references to dom objects + this.canvas = null; + this.container = null; + + // clear our reference to the main element - they will need to pass it in again, creating a new viewer + this.element = null; + }, + + /** + * @function + * @return {Boolean} + */ + isMouseNavEnabled: function () { + return this.innerTracker.isTracking(); + }, + + /** + * @function + * @param {Boolean} enabled - true to enable, false to disable + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:mouse-enabled + */ + setMouseNavEnabled: function( enabled ){ + this.innerTracker.setTracking( enabled ); + this.outerTracker.setTracking( enabled ); + /** + * Raised when mouse/touch navigation is enabled or disabled (see {@link OpenSeadragon.Viewer#setMouseNavEnabled}). + * + * @event mouse-enabled + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Boolean} enabled + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'mouse-enabled', { enabled: enabled } ); + return this; + }, + + + /** + * @function + * @return {Boolean} + */ + areControlsEnabled: function () { + var enabled = this.controls.length, + i; + for( i = 0; i < this.controls.length; i++ ){ + enabled = enabled && this.controls[ i ].isVisibile(); + } + return enabled; + }, + + + /** + * Shows or hides the controls (e.g. the default navigation buttons). + * + * @function + * @param {Boolean} true to show, false to hide. + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:controls-enabled + */ + setControlsEnabled: function( enabled ) { + if( enabled ){ + abortControlsAutoHide( this ); + } else { + beginControlsAutoHide( this ); + } + /** + * Raised when the navigation controls are shown or hidden (see {@link OpenSeadragon.Viewer#setControlsEnabled}). + * + * @event controls-enabled + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Boolean} enabled + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'controls-enabled', { enabled: enabled } ); + return this; + }, + + /** + * Turns debugging mode on or off for this viewer. + * + * @function + * @param {Boolean} true to turn debug on, false to turn debug off. + */ + setDebugMode: function(debugMode){ + + for (var i = 0; i < this.world.getItemCount(); i++) { + this.world.getItemAt(i).debugMode = debugMode; + } + + this.debugMode = debugMode; + this.forceRedraw(); + }, + + /** + * @function + * @return {Boolean} + */ + isFullPage: function () { + return THIS[ this.hash ].fullPage; + }, + + + /** + * Toggle full page mode. + * @function + * @param {Boolean} fullPage + * If true, enter full page mode. If false, exit full page mode. + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:pre-full-page + * @fires OpenSeadragon.Viewer.event:full-page + */ + setFullPage: function( fullPage ) { + + var body = document.body, + bodyStyle = body.style, + docStyle = document.documentElement.style, + _this = this, + nodes, + i; + + //dont bother modifying the DOM if we are already in full page mode. + if ( fullPage == this.isFullPage() ) { + return this; + } + + var fullPageEventArgs = { + fullPage: fullPage, + preventDefaultAction: false + }; + /** + * Raised when the viewer is about to change to/from full-page mode (see {@link OpenSeadragon.Viewer#setFullPage}). + * + * @event pre-full-page + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Boolean} fullPage - True if entering full-page mode, false if exiting full-page mode. + * @property {Boolean} preventDefaultAction - Set to true to prevent full-page mode change. Default: false. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'pre-full-page', fullPageEventArgs ); + if ( fullPageEventArgs.preventDefaultAction ) { + return this; + } + + if ( fullPage ) { + + this.elementSize = $.getElementSize( this.element ); + this.pageScroll = $.getPageScroll(); + + this.elementMargin = this.element.style.margin; + this.element.style.margin = "0"; + this.elementPadding = this.element.style.padding; + this.element.style.padding = "0"; + + this.bodyMargin = bodyStyle.margin; + this.docMargin = docStyle.margin; + bodyStyle.margin = "0"; + docStyle.margin = "0"; + + this.bodyPadding = bodyStyle.padding; + this.docPadding = docStyle.padding; + bodyStyle.padding = "0"; + docStyle.padding = "0"; + + this.bodyWidth = bodyStyle.width; + this.docWidth = docStyle.width; + bodyStyle.width = "100%"; + docStyle.width = "100%"; + + this.bodyHeight = bodyStyle.height; + this.docHeight = docStyle.height; + bodyStyle.height = "100%"; + docStyle.height = "100%"; + + //when entering full screen on the ipad it wasnt sufficient to leave + //the body intact as only only the top half of the screen would + //respond to touch events on the canvas, while the bottom half treated + //them as touch events on the document body. Thus we remove and store + //the bodies elements and replace them when we leave full screen. + this.previousBody = []; + THIS[ this.hash ].prevElementParent = this.element.parentNode; + THIS[ this.hash ].prevNextSibling = this.element.nextSibling; + THIS[ this.hash ].prevElementWidth = this.element.style.width; + THIS[ this.hash ].prevElementHeight = this.element.style.height; + nodes = body.childNodes.length; + for ( i = 0; i < nodes; i++ ) { + this.previousBody.push( body.childNodes[ 0 ] ); + body.removeChild( body.childNodes[ 0 ] ); + } + + //If we've got a toolbar, we need to enable the user to use css to + //preserve it in fullpage mode + if ( this.toolbar && this.toolbar.element ) { + //save a reference to the parent so we can put it back + //in the long run we need a better strategy + this.toolbar.parentNode = this.toolbar.element.parentNode; + this.toolbar.nextSibling = this.toolbar.element.nextSibling; + body.appendChild( this.toolbar.element ); + + //Make sure the user has some ability to style the toolbar based + //on the mode + $.addClass( this.toolbar.element, 'fullpage' ); + } + + $.addClass( this.element, 'fullpage' ); + body.appendChild( this.element ); + + this.element.style.height = $.getWindowSize().y + 'px'; + this.element.style.width = $.getWindowSize().x + 'px'; + + if ( this.toolbar && this.toolbar.element ) { + this.element.style.height = ( + $.getElementSize( this.element ).y - $.getElementSize( this.toolbar.element ).y + ) + 'px'; + } + + THIS[ this.hash ].fullPage = true; + + // mouse will be inside container now + $.delegate( this, onContainerEnter )( {} ); + + } else { + + this.element.style.margin = this.elementMargin; + this.element.style.padding = this.elementPadding; + + bodyStyle.margin = this.bodyMargin; + docStyle.margin = this.docMargin; + + bodyStyle.padding = this.bodyPadding; + docStyle.padding = this.docPadding; + + bodyStyle.width = this.bodyWidth; + docStyle.width = this.docWidth; + + bodyStyle.height = this.bodyHeight; + docStyle.height = this.docHeight; + + body.removeChild( this.element ); + nodes = this.previousBody.length; + for ( i = 0; i < nodes; i++ ) { + body.appendChild( this.previousBody.shift() ); + } + + $.removeClass( this.element, 'fullpage' ); + THIS[ this.hash ].prevElementParent.insertBefore( + this.element, + THIS[ this.hash ].prevNextSibling + ); + + //If we've got a toolbar, we need to enable the user to use css to + //reset it to its original state + if ( this.toolbar && this.toolbar.element ) { + body.removeChild( this.toolbar.element ); + + //Make sure the user has some ability to style the toolbar based + //on the mode + $.removeClass( this.toolbar.element, 'fullpage' ); + + this.toolbar.parentNode.insertBefore( + this.toolbar.element, + this.toolbar.nextSibling + ); + delete this.toolbar.parentNode; + delete this.toolbar.nextSibling; + } + + this.element.style.width = THIS[ this.hash ].prevElementWidth; + this.element.style.height = THIS[ this.hash ].prevElementHeight; + + // After exiting fullPage or fullScreen, it can take some time + // before the browser can actually set the scroll. + var restoreScrollCounter = 0; + var restoreScroll = function() { + $.setPageScroll( _this.pageScroll ); + var pageScroll = $.getPageScroll(); + restoreScrollCounter++; + if (restoreScrollCounter < 10 && + (pageScroll.x !== _this.pageScroll.x || + pageScroll.y !== _this.pageScroll.y)) { + $.requestAnimationFrame( restoreScroll ); + } + }; + $.requestAnimationFrame( restoreScroll ); + + THIS[ this.hash ].fullPage = false; + + // mouse will likely be outside now + $.delegate( this, onContainerExit )( { } ); + + } + + if ( this.navigator && this.viewport ) { + this.navigator.update( this.viewport ); + } + + /** + * Raised when the viewer has changed to/from full-page mode (see {@link OpenSeadragon.Viewer#setFullPage}). + * + * @event full-page + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Boolean} fullPage - True if changed to full-page mode, false if exited full-page mode. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'full-page', { fullPage: fullPage } ); + + return this; + }, + + /** + * Toggle full screen mode if supported. Toggle full page mode otherwise. + * @function + * @param {Boolean} fullScreen + * If true, enter full screen mode. If false, exit full screen mode. + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:pre-full-screen + * @fires OpenSeadragon.Viewer.event:full-screen + */ + setFullScreen: function( fullScreen ) { + var _this = this; + + if ( !$.supportsFullScreen ) { + return this.setFullPage( fullScreen ); + } + + if ( $.isFullScreen() === fullScreen ) { + return this; + } + + var fullScreeEventArgs = { + fullScreen: fullScreen, + preventDefaultAction: false + }; + /** + * Raised when the viewer is about to change to/from full-screen mode (see {@link OpenSeadragon.Viewer#setFullScreen}). + * Note: the pre-full-screen event is not raised when the user is exiting + * full-screen mode by pressing the Esc key. In that case, consider using + * the full-screen, pre-full-page or full-page events. + * + * @event pre-full-screen + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Boolean} fullScreen - True if entering full-screen mode, false if exiting full-screen mode. + * @property {Boolean} preventDefaultAction - Set to true to prevent full-screen mode change. Default: false. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'pre-full-screen', fullScreeEventArgs ); + if ( fullScreeEventArgs.preventDefaultAction ) { + return this; + } + + if ( fullScreen ) { + + this.setFullPage( true ); + // If the full page mode is not actually entered, we need to prevent + // the full screen mode. + if ( !this.isFullPage() ) { + return this; + } + + this.fullPageStyleWidth = this.element.style.width; + this.fullPageStyleHeight = this.element.style.height; + this.element.style.width = '100%'; + this.element.style.height = '100%'; + + var onFullScreenChange = function() { + var isFullScreen = $.isFullScreen(); + if ( !isFullScreen ) { + $.removeEvent( document, $.fullScreenEventName, onFullScreenChange ); + $.removeEvent( document, $.fullScreenErrorEventName, onFullScreenChange ); + + _this.setFullPage( false ); + if ( _this.isFullPage() ) { + _this.element.style.width = _this.fullPageStyleWidth; + _this.element.style.height = _this.fullPageStyleHeight; + } + } + if ( _this.navigator && _this.viewport ) { + _this.navigator.update( _this.viewport ); + } + /** + * Raised when the viewer has changed to/from full-screen mode (see {@link OpenSeadragon.Viewer#setFullScreen}). + * + * @event full-screen + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Boolean} fullScreen - True if changed to full-screen mode, false if exited full-screen mode. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( 'full-screen', { fullScreen: isFullScreen } ); + }; + $.addEvent( document, $.fullScreenEventName, onFullScreenChange ); + $.addEvent( document, $.fullScreenErrorEventName, onFullScreenChange ); + + $.requestFullScreen( document.body ); + + } else { + $.exitFullScreen(); + } + return this; + }, + + /** + * @function + * @return {Boolean} + */ + isVisible: function () { + return this.container.style.visibility != "hidden"; + }, + + + /** + * @function + * @param {Boolean} visible + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:visible + */ + setVisible: function( visible ){ + this.container.style.visibility = visible ? "" : "hidden"; + /** + * Raised when the viewer is shown or hidden (see {@link OpenSeadragon.Viewer#setVisible}). + * + * @event visible + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Boolean} visible + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'visible', { visible: visible } ); + return this; + }, + + /** + * Add a tiled image to the viewer. + * options.tileSource can be anything that {@link OpenSeadragon.Viewer#open} + * supports except arrays of images. + * Note that you can specify options.width or options.height, but not both. + * The other dimension will be calculated according to the item's aspect ratio. + * If collectionMode is on (see {@link OpenSeadragon.Options}), the new image is + * automatically arranged with the others. + * @function + * @param {Object} options + * @param {String|Object|Function} options.tileSource - The TileSource specifier. + * A String implies a url used to determine the tileSource implementation + * based on the file extension of url. JSONP is implied by *.js, + * otherwise the url is retrieved as text and the resulting text is + * introspected to determine if its json, xml, or text and parsed. + * An Object implies an inline configuration which has a single + * property sufficient for being able to determine tileSource + * implementation. If the object has a property which is a function + * named 'getTileUrl', it is treated as a custom TileSource. + * @param {Number} [options.index] The index of the item. Added on top of + * all other items if not specified. + * @param {Boolean} [options.replace=false] If true, the item at options.index will be + * removed and the new item is added in its place. options.tileSource will be + * interpreted and fetched if necessary before the old item is removed to avoid leaving + * a gap in the world. + * @param {Number} [options.x=0] The X position for the image in viewport coordinates. + * @param {Number} [options.y=0] The Y position for the image in viewport coordinates. + * @param {Number} [options.width=1] The width for the image in viewport coordinates. + * @param {Number} [options.height] The height for the image in viewport coordinates. + * @param {OpenSeadragon.Rect} [options.fitBounds] The bounds in viewport coordinates + * to fit the image into. If specified, x, y, width and height get ignored. + * @param {OpenSeadragon.Placement} [options.fitBoundsPlacement=OpenSeadragon.Placement.CENTER] + * How to anchor the image in the bounds if options.fitBounds is set. + * @param {OpenSeadragon.Rect} [options.clip] - An area, in image pixels, to clip to + * (portions of the image outside of this area will not be visible). Only works on + * browsers that support the HTML5 canvas. + * @param {Number} [options.opacity=1] Proportional opacity of the tiled images (1=opaque, 0=hidden) + * @param {Boolean} [options.preload=false] Default switch for loading hidden images (true loads, false blocks) + * @param {Number} [options.degrees=0] Initial rotation of the tiled image around + * its top left corner in degrees. + * @param {String} [options.compositeOperation] How the image is composited onto other images. + * @param {String} [options.crossOriginPolicy] The crossOriginPolicy for this specific image, + * overriding viewer.crossOriginPolicy. + * @param {Boolean} [options.ajaxWithCredentials] Whether to set withCredentials on tile AJAX + * @param {Boolean} [options.loadTilesWithAjax] + * Whether to load tile data using AJAX requests. + * Defaults to the setting in {@link OpenSeadragon.Options}. + * @param {Object} [options.ajaxHeaders] + * A set of headers to include when making tile AJAX requests. + * Note that these headers will be merged over any headers specified in {@link OpenSeadragon.Options}. + * Specifying a falsy value for a header will clear its existing value set at the Viewer level (if any). + * requests. + * @param {Function} [options.success] A function that gets called when the image is + * successfully added. It's passed the event object which contains a single property: + * "item", the resulting TiledImage. + * @param {Function} [options.error] A function that gets called if the image is + * unable to be added. It's passed the error event object, which contains "message" + * and "source" properties. + * @param {Boolean} [options.collectionImmediately=false] If collectionMode is on, + * specifies whether to snap to the new arrangement immediately or to animate to it. + * @param {String|CanvasGradient|CanvasPattern|Function} [options.placeholderFillStyle] - See {@link OpenSeadragon.Options}. + * @fires OpenSeadragon.World.event:add-item + * @fires OpenSeadragon.Viewer.event:add-item-failed + */ + addTiledImage: function( options ) { + $.console.assert(options, "[Viewer.addTiledImage] options is required"); + $.console.assert(options.tileSource, "[Viewer.addTiledImage] options.tileSource is required"); + $.console.assert(!options.replace || (options.index > -1 && options.index < this.world.getItemCount()), + "[Viewer.addTiledImage] if options.replace is used, options.index must be a valid index in Viewer.world"); + + var _this = this; + + if (options.replace) { + options.replaceItem = _this.world.getItemAt(options.index); + } + + this._hideMessage(); + + if (options.placeholderFillStyle === undefined) { + options.placeholderFillStyle = this.placeholderFillStyle; + } + if (options.opacity === undefined) { + options.opacity = this.opacity; + } + if (options.preload === undefined) { + options.preload = this.preload; + } + if (options.compositeOperation === undefined) { + options.compositeOperation = this.compositeOperation; + } + if (options.crossOriginPolicy === undefined) { + options.crossOriginPolicy = options.tileSource.crossOriginPolicy !== undefined ? options.tileSource.crossOriginPolicy : this.crossOriginPolicy; + } + if (options.ajaxWithCredentials === undefined) { + options.ajaxWithCredentials = this.ajaxWithCredentials; + } + if (options.loadTilesWithAjax === undefined) { + options.loadTilesWithAjax = this.loadTilesWithAjax; + } + if (options.ajaxHeaders === undefined || options.ajaxHeaders === null) { + options.ajaxHeaders = this.ajaxHeaders; + } else if ($.isPlainObject(options.ajaxHeaders) && $.isPlainObject(this.ajaxHeaders)) { + options.ajaxHeaders = $.extend({}, this.ajaxHeaders, options.ajaxHeaders); + } + + var myQueueItem = { + options: options + }; + + function raiseAddItemFailed( event ) { + for (var i = 0; i < _this._loadQueue.length; i++) { + if (_this._loadQueue[i] === myQueueItem) { + _this._loadQueue.splice(i, 1); + break; + } + } + + if (_this._loadQueue.length === 0) { + refreshWorld(myQueueItem); + } + + /** + * Raised when an error occurs while adding a item. + * @event add-item-failed + * @memberOf OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {String} message + * @property {String} source + * @property {Object} options The options passed to the addTiledImage method. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( 'add-item-failed', event ); + + if (options.error) { + options.error(event); + } + } + + function refreshWorld(theItem) { + if (_this.collectionMode) { + _this.world.arrange({ + immediately: theItem.options.collectionImmediately, + rows: _this.collectionRows, + columns: _this.collectionColumns, + layout: _this.collectionLayout, + tileSize: _this.collectionTileSize, + tileMargin: _this.collectionTileMargin + }); + _this.world.setAutoRefigureSizes(true); + } + } + + if ($.isArray(options.tileSource)) { + setTimeout(function() { + raiseAddItemFailed({ + message: "[Viewer.addTiledImage] Sequences can not be added; add them one at a time instead.", + source: options.tileSource, + options: options + }); + }); + return; + } + + this._loadQueue.push(myQueueItem); + + function processReadyItems() { + var queueItem, tiledImage, optionsClone; + while (_this._loadQueue.length) { + queueItem = _this._loadQueue[0]; + if (!queueItem.tileSource) { + break; + } + + _this._loadQueue.splice(0, 1); + + if (queueItem.options.replace) { + var newIndex = _this.world.getIndexOfItem(queueItem.options.replaceItem); + if (newIndex != -1) { + queueItem.options.index = newIndex; + } + _this.world.removeItem(queueItem.options.replaceItem); + } + + tiledImage = new $.TiledImage({ + viewer: _this, + source: queueItem.tileSource, + viewport: _this.viewport, + drawer: _this.drawer, + tileCache: _this.tileCache, + imageLoader: _this.imageLoader, + x: queueItem.options.x, + y: queueItem.options.y, + width: queueItem.options.width, + height: queueItem.options.height, + fitBounds: queueItem.options.fitBounds, + fitBoundsPlacement: queueItem.options.fitBoundsPlacement, + clip: queueItem.options.clip, + placeholderFillStyle: queueItem.options.placeholderFillStyle, + opacity: queueItem.options.opacity, + preload: queueItem.options.preload, + degrees: queueItem.options.degrees, + compositeOperation: queueItem.options.compositeOperation, + springStiffness: _this.springStiffness, + animationTime: _this.animationTime, + minZoomImageRatio: _this.minZoomImageRatio, + wrapHorizontal: _this.wrapHorizontal, + wrapVertical: _this.wrapVertical, + immediateRender: _this.immediateRender, + blendTime: _this.blendTime, + alwaysBlend: _this.alwaysBlend, + minPixelRatio: _this.minPixelRatio, + smoothTileEdgesMinZoom: _this.smoothTileEdgesMinZoom, + iOSDevice: _this.iOSDevice, + crossOriginPolicy: queueItem.options.crossOriginPolicy, + ajaxWithCredentials: queueItem.options.ajaxWithCredentials, + loadTilesWithAjax: queueItem.options.loadTilesWithAjax, + ajaxHeaders: queueItem.options.ajaxHeaders, + debugMode: _this.debugMode + }); + + if (_this.collectionMode) { + _this.world.setAutoRefigureSizes(false); + } + _this.world.addItem( tiledImage, { + index: queueItem.options.index + }); + + if (_this._loadQueue.length === 0) { + //this restores the autoRefigureSizes flag to true. + refreshWorld(queueItem); + } + + if (_this.world.getItemCount() === 1 && !_this.preserveViewport) { + _this.viewport.goHome(true); + } + + if (_this.navigator) { + optionsClone = $.extend({}, queueItem.options, { + replace: false, // navigator already removed the layer, nothing to replace + originalTiledImage: tiledImage, + tileSource: queueItem.tileSource + }); + + _this.navigator.addTiledImage(optionsClone); + } + + if (queueItem.options.success) { + queueItem.options.success({ + item: tiledImage + }); + } + } + } + + getTileSourceImplementation( this, options.tileSource, options, function( tileSource ) { + + myQueueItem.tileSource = tileSource; + + // add everybody at the front of the queue that's ready to go + processReadyItems(); + }, function( event ) { + event.options = options; + raiseAddItemFailed(event); + + // add everybody at the front of the queue that's ready to go + processReadyItems(); + } ); + }, + + /** + * Add a simple image to the viewer. + * The options are the same as the ones in {@link OpenSeadragon.Viewer#addTiledImage} + * except for options.tileSource which is replaced by options.url. + * @function + * @param {Object} options - See {@link OpenSeadragon.Viewer#addTiledImage} + * for all the options + * @param {String} options.url - The URL of the image to add. + * @fires OpenSeadragon.World.event:add-item + * @fires OpenSeadragon.Viewer.event:add-item-failed + */ + addSimpleImage: function(options) { + $.console.assert(options, "[Viewer.addSimpleImage] options is required"); + $.console.assert(options.url, "[Viewer.addSimpleImage] options.url is required"); + + var opts = $.extend({}, options, { + tileSource: { + type: 'image', + url: options.url + } + }); + delete opts.url; + this.addTiledImage(opts); + }, + + // deprecated + addLayer: function( options ) { + var _this = this; + + $.console.error( "[Viewer.addLayer] this function is deprecated; use Viewer.addTiledImage() instead." ); + + var optionsClone = $.extend({}, options, { + success: function(event) { + _this.raiseEvent("add-layer", { + options: options, + drawer: event.item + }); + }, + error: function(event) { + _this.raiseEvent("add-layer-failed", event); + } + }); + + this.addTiledImage(optionsClone); + return this; + }, + + // deprecated + getLayerAtLevel: function( level ) { + $.console.error( "[Viewer.getLayerAtLevel] this function is deprecated; use World.getItemAt() instead." ); + return this.world.getItemAt(level); + }, + + // deprecated + getLevelOfLayer: function( drawer ) { + $.console.error( "[Viewer.getLevelOfLayer] this function is deprecated; use World.getIndexOfItem() instead." ); + return this.world.getIndexOfItem(drawer); + }, + + // deprecated + getLayersCount: function() { + $.console.error( "[Viewer.getLayersCount] this function is deprecated; use World.getItemCount() instead." ); + return this.world.getItemCount(); + }, + + // deprecated + setLayerLevel: function( drawer, level ) { + $.console.error( "[Viewer.setLayerLevel] this function is deprecated; use World.setItemIndex() instead." ); + return this.world.setItemIndex(drawer, level); + }, + + // deprecated + removeLayer: function( drawer ) { + $.console.error( "[Viewer.removeLayer] this function is deprecated; use World.removeItem() instead." ); + return this.world.removeItem(drawer); + }, + + /** + * Force the viewer to redraw its contents. + * @returns {OpenSeadragon.Viewer} Chainable. + */ + forceRedraw: function() { + THIS[ this.hash ].forceRedraw = true; + return this; + }, + + /** + * @function + * @return {OpenSeadragon.Viewer} Chainable. + */ + bindSequenceControls: function(){ + + ////////////////////////////////////////////////////////////////////////// + // Image Sequence Controls + ////////////////////////////////////////////////////////////////////////// + var onFocusHandler = $.delegate( this, onFocus ), + onBlurHandler = $.delegate( this, onBlur ), + onNextHandler = $.delegate( this, onNext ), + onPreviousHandler = $.delegate( this, onPrevious ), + navImages = this.navImages, + useGroup = true; + + if( this.showSequenceControl ){ + + if( this.previousButton || this.nextButton ){ + //if we are binding to custom buttons then layout and + //grouping is the responsibility of the page author + useGroup = false; + } + + this.previousButton = new $.Button({ + element: this.previousButton ? $.getElement( this.previousButton ) : null, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + tooltip: $.getString( "Tooltips.PreviousPage" ), + srcRest: resolveUrl( this.prefixUrl, navImages.previous.REST ), + srcGroup: resolveUrl( this.prefixUrl, navImages.previous.GROUP ), + srcHover: resolveUrl( this.prefixUrl, navImages.previous.HOVER ), + srcDown: resolveUrl( this.prefixUrl, navImages.previous.DOWN ), + onRelease: onPreviousHandler, + onFocus: onFocusHandler, + onBlur: onBlurHandler + }); + + this.nextButton = new $.Button({ + element: this.nextButton ? $.getElement( this.nextButton ) : null, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + tooltip: $.getString( "Tooltips.NextPage" ), + srcRest: resolveUrl( this.prefixUrl, navImages.next.REST ), + srcGroup: resolveUrl( this.prefixUrl, navImages.next.GROUP ), + srcHover: resolveUrl( this.prefixUrl, navImages.next.HOVER ), + srcDown: resolveUrl( this.prefixUrl, navImages.next.DOWN ), + onRelease: onNextHandler, + onFocus: onFocusHandler, + onBlur: onBlurHandler + }); + + if( !this.navPrevNextWrap ){ + this.previousButton.disable(); + } + + if (!this.tileSources || !this.tileSources.length) { + this.nextButton.disable(); + } + + if( useGroup ){ + this.paging = new $.ButtonGroup({ + buttons: [ + this.previousButton, + this.nextButton + ], + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold + }); + + this.pagingControl = this.paging.element; + + if( this.toolbar ){ + this.toolbar.addControl( + this.pagingControl, + {anchor: $.ControlAnchor.BOTTOM_RIGHT} + ); + }else{ + this.addControl( + this.pagingControl, + {anchor: this.sequenceControlAnchor || $.ControlAnchor.TOP_LEFT} + ); + } + } + } + return this; + }, + + + /** + * @function + * @return {OpenSeadragon.Viewer} Chainable. + */ + bindStandardControls: function(){ + ////////////////////////////////////////////////////////////////////////// + // Navigation Controls + ////////////////////////////////////////////////////////////////////////// + var beginZoomingInHandler = $.delegate( this, beginZoomingIn ), + endZoomingHandler = $.delegate( this, endZooming ), + doSingleZoomInHandler = $.delegate( this, doSingleZoomIn ), + beginZoomingOutHandler = $.delegate( this, beginZoomingOut ), + doSingleZoomOutHandler = $.delegate( this, doSingleZoomOut ), + onHomeHandler = $.delegate( this, onHome ), + onFullScreenHandler = $.delegate( this, onFullScreen ), + onRotateLeftHandler = $.delegate( this, onRotateLeft ), + onRotateRightHandler = $.delegate( this, onRotateRight ), + onFocusHandler = $.delegate( this, onFocus ), + onBlurHandler = $.delegate( this, onBlur ), + navImages = this.navImages, + buttons = [], + useGroup = true; + + + if ( this.showNavigationControl ) { + + if( this.zoomInButton || this.zoomOutButton || + this.homeButton || this.fullPageButton || + this.rotateLeftButton || this.rotateRightButton ) { + //if we are binding to custom buttons then layout and + //grouping is the responsibility of the page author + useGroup = false; + } + + if ( this.showZoomControl ) { + buttons.push( this.zoomInButton = new $.Button({ + element: this.zoomInButton ? $.getElement( this.zoomInButton ) : null, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + tooltip: $.getString( "Tooltips.ZoomIn" ), + srcRest: resolveUrl( this.prefixUrl, navImages.zoomIn.REST ), + srcGroup: resolveUrl( this.prefixUrl, navImages.zoomIn.GROUP ), + srcHover: resolveUrl( this.prefixUrl, navImages.zoomIn.HOVER ), + srcDown: resolveUrl( this.prefixUrl, navImages.zoomIn.DOWN ), + onPress: beginZoomingInHandler, + onRelease: endZoomingHandler, + onClick: doSingleZoomInHandler, + onEnter: beginZoomingInHandler, + onExit: endZoomingHandler, + onFocus: onFocusHandler, + onBlur: onBlurHandler + })); + + buttons.push( this.zoomOutButton = new $.Button({ + element: this.zoomOutButton ? $.getElement( this.zoomOutButton ) : null, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + tooltip: $.getString( "Tooltips.ZoomOut" ), + srcRest: resolveUrl( this.prefixUrl, navImages.zoomOut.REST ), + srcGroup: resolveUrl( this.prefixUrl, navImages.zoomOut.GROUP ), + srcHover: resolveUrl( this.prefixUrl, navImages.zoomOut.HOVER ), + srcDown: resolveUrl( this.prefixUrl, navImages.zoomOut.DOWN ), + onPress: beginZoomingOutHandler, + onRelease: endZoomingHandler, + onClick: doSingleZoomOutHandler, + onEnter: beginZoomingOutHandler, + onExit: endZoomingHandler, + onFocus: onFocusHandler, + onBlur: onBlurHandler + })); + } + + if ( this.showHomeControl ) { + buttons.push( this.homeButton = new $.Button({ + element: this.homeButton ? $.getElement( this.homeButton ) : null, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + tooltip: $.getString( "Tooltips.Home" ), + srcRest: resolveUrl( this.prefixUrl, navImages.home.REST ), + srcGroup: resolveUrl( this.prefixUrl, navImages.home.GROUP ), + srcHover: resolveUrl( this.prefixUrl, navImages.home.HOVER ), + srcDown: resolveUrl( this.prefixUrl, navImages.home.DOWN ), + onRelease: onHomeHandler, + onFocus: onFocusHandler, + onBlur: onBlurHandler + })); + } + + if ( this.showFullPageControl ) { + buttons.push( this.fullPageButton = new $.Button({ + element: this.fullPageButton ? $.getElement( this.fullPageButton ) : null, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + tooltip: $.getString( "Tooltips.FullPage" ), + srcRest: resolveUrl( this.prefixUrl, navImages.fullpage.REST ), + srcGroup: resolveUrl( this.prefixUrl, navImages.fullpage.GROUP ), + srcHover: resolveUrl( this.prefixUrl, navImages.fullpage.HOVER ), + srcDown: resolveUrl( this.prefixUrl, navImages.fullpage.DOWN ), + onRelease: onFullScreenHandler, + onFocus: onFocusHandler, + onBlur: onBlurHandler + })); + } + + if ( this.showRotationControl ) { + buttons.push( this.rotateLeftButton = new $.Button({ + element: this.rotateLeftButton ? $.getElement( this.rotateLeftButton ) : null, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + tooltip: $.getString( "Tooltips.RotateLeft" ), + srcRest: resolveUrl( this.prefixUrl, navImages.rotateleft.REST ), + srcGroup: resolveUrl( this.prefixUrl, navImages.rotateleft.GROUP ), + srcHover: resolveUrl( this.prefixUrl, navImages.rotateleft.HOVER ), + srcDown: resolveUrl( this.prefixUrl, navImages.rotateleft.DOWN ), + onRelease: onRotateLeftHandler, + onFocus: onFocusHandler, + onBlur: onBlurHandler + })); + + buttons.push( this.rotateRightButton = new $.Button({ + element: this.rotateRightButton ? $.getElement( this.rotateRightButton ) : null, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + tooltip: $.getString( "Tooltips.RotateRight" ), + srcRest: resolveUrl( this.prefixUrl, navImages.rotateright.REST ), + srcGroup: resolveUrl( this.prefixUrl, navImages.rotateright.GROUP ), + srcHover: resolveUrl( this.prefixUrl, navImages.rotateright.HOVER ), + srcDown: resolveUrl( this.prefixUrl, navImages.rotateright.DOWN ), + onRelease: onRotateRightHandler, + onFocus: onFocusHandler, + onBlur: onBlurHandler + })); + + } + + if ( useGroup ) { + this.buttons = new $.ButtonGroup({ + buttons: buttons, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold + }); + + this.navControl = this.buttons.element; + this.addHandler( 'open', $.delegate( this, lightUp ) ); + + if( this.toolbar ){ + this.toolbar.addControl( + this.navControl, + {anchor: this.navigationControlAnchor || $.ControlAnchor.TOP_LEFT} + ); + } else { + this.addControl( + this.navControl, + {anchor: this.navigationControlAnchor || $.ControlAnchor.TOP_LEFT} + ); + } + } + + } + return this; + }, + + /** + * Gets the active page of a sequence + * @function + * @return {Number} + */ + currentPage: function() { + return this._sequenceIndex; + }, + + /** + * @function + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:page + */ + goToPage: function( page ){ + if( this.tileSources && page >= 0 && page < this.tileSources.length ){ + /** + * Raised when the page is changed on a viewer configured with multiple image sources (see {@link OpenSeadragon.Viewer#goToPage}). + * + * @event page + * @memberof OpenSeadragon.Viewer + * @type {Object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Number} page - The page index. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'page', { page: page } ); + + this._sequenceIndex = page; + + this._updateSequenceButtons( page ); + + this.open( this.tileSources[ page ] ); + + if( this.referenceStrip ){ + this.referenceStrip.setFocus( page ); + } + } + + return this; + }, + + /** + * Adds an html element as an overlay to the current viewport. Useful for + * highlighting words or areas of interest on an image or other zoomable + * interface. The overlays added via this method are removed when the viewport + * is closed which include when changing page. + * @method + * @param {Element|String|Object} element - A reference to an element or an id for + * the element which will be overlayed. Or an Object specifying the configuration for the overlay. + * If using an object, see {@link OpenSeadragon.Overlay} for a list of + * all available options. + * @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or + * rectangle which will be overlayed. This is a viewport relative location. + * @param {OpenSeadragon.Placement} placement - The position of the + * viewport which the location coordinates will be treated as relative + * to. + * @param {function} onDraw - If supplied the callback is called when the overlay + * needs to be drawn. It it the responsibility of the callback to do any drawing/positioning. + * It is passed position, size and element. + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:add-overlay + */ + addOverlay: function( element, location, placement, onDraw ) { + var options; + if( $.isPlainObject( element ) ){ + options = element; + } else { + options = { + element: element, + location: location, + placement: placement, + onDraw: onDraw + }; + } + + element = $.getElement( options.element ); + + if ( getOverlayIndex( this.currentOverlays, element ) >= 0 ) { + // they're trying to add a duplicate overlay + return this; + } + + var overlay = getOverlayObject( this, options); + this.currentOverlays.push(overlay); + overlay.drawHTML( this.overlaysContainer, this.viewport ); + + /** + * Raised when an overlay is added to the viewer (see {@link OpenSeadragon.Viewer#addOverlay}). + * + * @event add-overlay + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Element} element - The overlay element. + * @property {OpenSeadragon.Point|OpenSeadragon.Rect} location + * @property {OpenSeadragon.Placement} placement + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'add-overlay', { + element: element, + location: options.location, + placement: options.placement + }); + return this; + }, + + /** + * Updates the overlay represented by the reference to the element or + * element id moving it to the new location, relative to the new placement. + * @method + * @param {Element|String} element - A reference to an element or an id for + * the element which is overlayed. + * @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or + * rectangle which will be overlayed. This is a viewport relative location. + * @param {OpenSeadragon.Placement} placement - The position of the + * viewport which the location coordinates will be treated as relative + * to. + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:update-overlay + */ + updateOverlay: function( element, location, placement ) { + var i; + + element = $.getElement( element ); + i = getOverlayIndex( this.currentOverlays, element ); + + if ( i >= 0 ) { + this.currentOverlays[ i ].update( location, placement ); + THIS[ this.hash ].forceRedraw = true; + /** + * Raised when an overlay's location or placement changes + * (see {@link OpenSeadragon.Viewer#updateOverlay}). + * + * @event update-overlay + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the + * Viewer which raised the event. + * @property {Element} element + * @property {OpenSeadragon.Point|OpenSeadragon.Rect} location + * @property {OpenSeadragon.Placement} placement + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'update-overlay', { + element: element, + location: location, + placement: placement + }); + } + return this; + }, + + /** + * Removes an overlay identified by the reference element or element id + * and schedules an update. + * @method + * @param {Element|String} element - A reference to the element or an + * element id which represent the ovelay content to be removed. + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:remove-overlay + */ + removeOverlay: function( element ) { + var i; + + element = $.getElement( element ); + i = getOverlayIndex( this.currentOverlays, element ); + + if ( i >= 0 ) { + this.currentOverlays[ i ].destroy(); + this.currentOverlays.splice( i, 1 ); + THIS[ this.hash ].forceRedraw = true; + /** + * Raised when an overlay is removed from the viewer + * (see {@link OpenSeadragon.Viewer#removeOverlay}). + * + * @event remove-overlay + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the + * Viewer which raised the event. + * @property {Element} element - The overlay element. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'remove-overlay', { + element: element + }); + } + return this; + }, + + /** + * Removes all currently configured Overlays from this Viewer and schedules + * an update. + * @method + * @return {OpenSeadragon.Viewer} Chainable. + * @fires OpenSeadragon.Viewer.event:clear-overlay + */ + clearOverlays: function() { + while ( this.currentOverlays.length > 0 ) { + this.currentOverlays.pop().destroy(); + } + THIS[ this.hash ].forceRedraw = true; + /** + * Raised when all overlays are removed from the viewer (see {@link OpenSeadragon.Drawer#clearOverlays}). + * + * @event clear-overlay + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'clear-overlay', {} ); + return this; + }, + + /** + * Finds an overlay identified by the reference element or element id + * and returns it as an object, return null if not found. + * @method + * @param {Element|String} element - A reference to the element or an + * element id which represents the overlay content. + * @return {OpenSeadragon.Overlay} the matching overlay or null if none found. + */ + getOverlayById: function( element ) { + var i; + + element = $.getElement( element ); + i = getOverlayIndex( this.currentOverlays, element ); + + if (i >= 0) { + return this.currentOverlays[i]; + } else { + return null; + } + }, + + /** + * Updates the sequence buttons. + * @function OpenSeadragon.Viewer.prototype._updateSequenceButtons + * @private + * @param {Number} Sequence Value + */ + _updateSequenceButtons: function( page ) { + + if ( this.nextButton ) { + if(!this.tileSources || this.tileSources.length - 1 === page) { + //Disable next button + if ( !this.navPrevNextWrap ) { + this.nextButton.disable(); + } + } else { + this.nextButton.enable(); + } + } + if ( this.previousButton ) { + if ( page > 0 ) { + //Enable previous button + this.previousButton.enable(); + } else { + if ( !this.navPrevNextWrap ) { + this.previousButton.disable(); + } + } + } + }, + + /** + * Display a message in the viewport + * @function OpenSeadragon.Viewer.prototype._showMessage + * @private + * @param {String} text message + */ + _showMessage: function ( message ) { + this._hideMessage(); + + var div = $.makeNeutralElement( "div" ); + div.appendChild( document.createTextNode( message ) ); + + this.messageDiv = $.makeCenteredNode( div ); + + $.addClass(this.messageDiv, "openseadragon-message"); + + this.container.appendChild( this.messageDiv ); + }, + + /** + * Hide any currently displayed viewport message + * @function OpenSeadragon.Viewer.prototype._hideMessage + * @private + */ + _hideMessage: function () { + var div = this.messageDiv; + if (div) { + div.parentNode.removeChild(div); + delete this.messageDiv; + } + }, + + /** + * Gets this viewer's gesture settings for the given pointer device type. + * @method + * @param {String} type - The pointer device type to get the gesture settings for ("mouse", "touch", "pen", etc.). + * @return {OpenSeadragon.GestureSettings} + */ + gestureSettingsByDeviceType: function ( type ) { + switch ( type ) { + case 'mouse': + return this.gestureSettingsMouse; + case 'touch': + return this.gestureSettingsTouch; + case 'pen': + return this.gestureSettingsPen; + default: + return this.gestureSettingsUnknown; + } + }, + + // private + _drawOverlays: function() { + var i, + length = this.currentOverlays.length; + for ( i = 0; i < length; i++ ) { + this.currentOverlays[ i ].drawHTML( this.overlaysContainer, this.viewport ); + } + }, + + /** + * Cancel the "in flight" images. + */ + _cancelPendingImages: function() { + this._loadQueue = []; + }, + + /** + * Removes the reference strip and disables displaying it. + * @function + */ + removeReferenceStrip: function() { + this.showReferenceStrip = false; + + if (this.referenceStrip) { + this.referenceStrip.destroy(); + this.referenceStrip = null; + } + }, + + /** + * Enables and displays the reference strip based on the currently set tileSources. + * Works only when the Viewer has sequenceMode set to true. + * @function + */ + addReferenceStrip: function() { + this.showReferenceStrip = true; + + if (this.sequenceMode) { + if (this.referenceStrip) { + return; + } + + if (this.tileSources.length && this.tileSources.length > 1) { + this.referenceStrip = new $.ReferenceStrip({ + id: this.referenceStripElement, + position: this.referenceStripPosition, + sizeRatio: this.referenceStripSizeRatio, + scroll: this.referenceStripScroll, + height: this.referenceStripHeight, + width: this.referenceStripWidth, + tileSources: this.tileSources, + prefixUrl: this.prefixUrl, + viewer: this + }); + + this.referenceStrip.setFocus( this._sequenceIndex ); + } + } else { + $.console.warn('Attempting to display a reference strip while "sequenceMode" is off.'); + } + } +}); + + +/** + * _getSafeElemSize is like getElementSize(), but refuses to return 0 for x or y, + * which was causing some calling operations to return NaN. + * @returns {Point} + * @private + */ +function _getSafeElemSize (oElement) { + oElement = $.getElement( oElement ); + + return new $.Point( + (oElement.clientWidth === 0 ? 1 : oElement.clientWidth), + (oElement.clientHeight === 0 ? 1 : oElement.clientHeight) + ); +} + + +/** + * @function + * @private + */ +function getTileSourceImplementation( viewer, tileSource, imgOptions, successCallback, + failCallback ) { + var _this = viewer; + + //allow plain xml strings or json strings to be parsed here + if ( $.type( tileSource ) == 'string' ) { + //xml should start with "<" and end with ">" + if ( tileSource.match( /^\s*<.*>\s*$/ ) ) { + tileSource = $.parseXml( tileSource ); + //json should start with "{" or "[" and end with "}" or "]" + } else if ( tileSource.match(/^\s*[\{\[].*[\}\]]\s*$/ ) ) { + try { + var tileSourceJ = $.parseJSON(tileSource); + tileSource = tileSourceJ; + } catch (e) { + //tileSource = tileSource; + } + } + } + + function waitUntilReady(tileSource, originalTileSource) { + if (tileSource.ready) { + successCallback(tileSource); + } else { + tileSource.addHandler('ready', function () { + successCallback(tileSource); + }); + tileSource.addHandler('open-failed', function (event) { + failCallback({ + message: event.message, + source: originalTileSource + }); + }); + } + } + + setTimeout( function() { + if ( $.type( tileSource ) == 'string' ) { + //If its still a string it means it must be a url at this point + tileSource = new $.TileSource({ + url: tileSource, + crossOriginPolicy: imgOptions.crossOriginPolicy !== undefined ? + imgOptions.crossOriginPolicy : viewer.crossOriginPolicy, + ajaxWithCredentials: viewer.ajaxWithCredentials, + ajaxHeaders: viewer.ajaxHeaders, + useCanvas: viewer.useCanvas, + success: function( event ) { + successCallback( event.tileSource ); + } + }); + tileSource.addHandler( 'open-failed', function( event ) { + failCallback( event ); + } ); + + } else if ($.isPlainObject(tileSource) || tileSource.nodeType) { + if (tileSource.crossOriginPolicy === undefined && + (imgOptions.crossOriginPolicy !== undefined || viewer.crossOriginPolicy !== undefined)) { + tileSource.crossOriginPolicy = imgOptions.crossOriginPolicy !== undefined ? + imgOptions.crossOriginPolicy : viewer.crossOriginPolicy; + } + if (tileSource.ajaxWithCredentials === undefined) { + tileSource.ajaxWithCredentials = viewer.ajaxWithCredentials; + } + if (tileSource.useCanvas === undefined) { + tileSource.useCanvas = viewer.useCanvas; + } + + if ( $.isFunction( tileSource.getTileUrl ) ) { + //Custom tile source + var customTileSource = new $.TileSource( tileSource ); + customTileSource.getTileUrl = tileSource.getTileUrl; + successCallback( customTileSource ); + } else { + //inline configuration + var $TileSource = $.TileSource.determineType( _this, tileSource ); + if ( !$TileSource ) { + failCallback( { + message: "Unable to load TileSource", + source: tileSource + }); + return; + } + var options = $TileSource.prototype.configure.apply( _this, [ tileSource ] ); + waitUntilReady(new $TileSource(options), tileSource); + } + } else { + //can assume it's already a tile source implementation + waitUntilReady(tileSource, tileSource); + } + }); +} + +function getOverlayObject( viewer, overlay ) { + if ( overlay instanceof $.Overlay ) { + return overlay; + } + + var element = null; + if ( overlay.element ) { + element = $.getElement( overlay.element ); + } else { + var id = overlay.id ? + overlay.id : + "openseadragon-overlay-" + Math.floor( Math.random() * 10000000 ); + + element = $.getElement( overlay.id ); + if ( !element ) { + element = document.createElement( "a" ); + element.href = "#/overlay/" + id; + } + element.id = id; + $.addClass( element, overlay.className ? + overlay.className : + "openseadragon-overlay" + ); + } + + var location = overlay.location; + var width = overlay.width; + var height = overlay.height; + if (!location) { + var x = overlay.x; + var y = overlay.y; + if (overlay.px !== undefined) { + var rect = viewer.viewport.imageToViewportRectangle(new $.Rect( + overlay.px, + overlay.py, + width || 0, + height || 0)); + x = rect.x; + y = rect.y; + width = width !== undefined ? rect.width : undefined; + height = height !== undefined ? rect.height : undefined; + } + location = new $.Point(x, y); + } + + var placement = overlay.placement; + if (placement && $.type(placement) === "string") { + placement = $.Placement[overlay.placement.toUpperCase()]; + } + + return new $.Overlay({ + element: element, + location: location, + placement: placement, + onDraw: overlay.onDraw, + checkResize: overlay.checkResize, + width: width, + height: height, + rotationMode: overlay.rotationMode + }); +} + +/** + * @private + * @inner + * Determines the index of the given overlay in the given overlays array. + */ +function getOverlayIndex( overlays, element ) { + var i; + for ( i = overlays.length - 1; i >= 0; i-- ) { + if ( overlays[ i ].element === element ) { + return i; + } + } + + return -1; +} + +/////////////////////////////////////////////////////////////////////////////// +// Schedulers provide the general engine for animation +/////////////////////////////////////////////////////////////////////////////// +function scheduleUpdate( viewer, updateFunc ){ + return $.requestAnimationFrame( function(){ + updateFunc( viewer ); + } ); +} + + +//provides a sequence in the fade animation +function scheduleControlsFade( viewer ) { + $.requestAnimationFrame( function(){ + updateControlsFade( viewer ); + }); +} + + +//initiates an animation to hide the controls +function beginControlsAutoHide( viewer ) { + if ( !viewer.autoHideControls ) { + return; + } + viewer.controlsShouldFade = true; + viewer.controlsFadeBeginTime = + $.now() + + viewer.controlsFadeDelay; + + window.setTimeout( function(){ + scheduleControlsFade( viewer ); + }, viewer.controlsFadeDelay ); +} + + +//determines if fade animation is done or continues the animation +function updateControlsFade( viewer ) { + var currentTime, + deltaTime, + opacity, + i; + if ( viewer.controlsShouldFade ) { + currentTime = $.now(); + deltaTime = currentTime - viewer.controlsFadeBeginTime; + opacity = 1.0 - deltaTime / viewer.controlsFadeLength; + + opacity = Math.min( 1.0, opacity ); + opacity = Math.max( 0.0, opacity ); + + for ( i = viewer.controls.length - 1; i >= 0; i--) { + if (viewer.controls[ i ].autoFade) { + viewer.controls[ i ].setOpacity( opacity ); + } + } + + if ( opacity > 0 ) { + // fade again + scheduleControlsFade( viewer ); + } + } +} + + +//stop the fade animation on the controls and show them +function abortControlsAutoHide( viewer ) { + var i; + viewer.controlsShouldFade = false; + for ( i = viewer.controls.length - 1; i >= 0; i-- ) { + viewer.controls[ i ].setOpacity( 1.0 ); + } +} + + + +/////////////////////////////////////////////////////////////////////////////// +// Default view event handlers. +/////////////////////////////////////////////////////////////////////////////// +function onFocus(){ + abortControlsAutoHide( this ); +} + +function onBlur(){ + beginControlsAutoHide( this ); + +} + +function onCanvasKeyDown( event ) { + if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { + switch( event.keyCode ){ + case 38://up arrow + if ( event.shift ) { + this.viewport.zoomBy(1.1); + } else { + this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, -40))); + } + this.viewport.applyConstraints(); + return false; + case 40://down arrow + if ( event.shift ) { + this.viewport.zoomBy(0.9); + } else { + this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, 40))); + } + this.viewport.applyConstraints(); + return false; + case 37://left arrow + this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(-40, 0))); + this.viewport.applyConstraints(); + return false; + case 39://right arrow + this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(40, 0))); + this.viewport.applyConstraints(); + return false; + default: + //console.log( 'navigator keycode %s', event.keyCode ); + return true; + } + } else { + return true; + } +} + +function onCanvasKeyPress( event ) { + if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { + switch( event.keyCode ){ + case 43://=|+ + case 61://=|+ + this.viewport.zoomBy(1.1); + this.viewport.applyConstraints(); + return false; + case 45://-|_ + this.viewport.zoomBy(0.9); + this.viewport.applyConstraints(); + return false; + case 48://0|) + this.viewport.goHome(); + this.viewport.applyConstraints(); + return false; + case 119://w + case 87://W + if ( event.shift ) { + this.viewport.zoomBy(1.1); + } else { + this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, -40))); + } + this.viewport.applyConstraints(); + return false; + case 115://s + case 83://S + if ( event.shift ) { + this.viewport.zoomBy(0.9); + } else { + this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, 40))); + } + this.viewport.applyConstraints(); + return false; + case 97://a + this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(-40, 0))); + this.viewport.applyConstraints(); + return false; + case 100://d + this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(40, 0))); + this.viewport.applyConstraints(); + return false; + default: + //console.log( 'navigator keycode %s', event.keyCode ); + return true; + } + } else { + return true; + } +} + +function onCanvasClick( event ) { + var gestureSettings; + + var haveKeyboardFocus = document.activeElement == this.canvas; + + // If we don't have keyboard focus, request it. + if ( !haveKeyboardFocus ) { + this.canvas.focus(); + } + + var canvasClickEventArgs = { + tracker: event.eventSource, + position: event.position, + quick: event.quick, + shift: event.shift, + originalEvent: event.originalEvent, + preventDefaultAction: event.preventDefaultAction + }; + + /** + * Raised when a mouse press/release or touch/remove occurs on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-click + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Boolean} quick - True only if the clickDistThreshold and clickTimeThreshold are both passed. Useful for differentiating between clicks and drags. + * @property {Boolean} shift - True if the shift key was pressed during this event. + * @property {Object} originalEvent - The original DOM event. + * @property {Boolean} preventDefaultAction - Set to true to prevent default click to zoom behaviour. Default: false. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-click', canvasClickEventArgs); + + if ( !canvasClickEventArgs.preventDefaultAction && this.viewport && event.quick ) { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); + if ( gestureSettings.clickToZoom ) { + this.viewport.zoomBy( + event.shift ? 1.0 / this.zoomPerClick : this.zoomPerClick, + this.viewport.pointFromPixel( event.position, true ) + ); + this.viewport.applyConstraints(); + } + } +} + +function onCanvasDblClick( event ) { + var gestureSettings; + + if ( !event.preventDefaultAction && this.viewport ) { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); + if ( gestureSettings.dblClickToZoom ) { + this.viewport.zoomBy( + event.shift ? 1.0 / this.zoomPerClick : this.zoomPerClick, + this.viewport.pointFromPixel( event.position, true ) + ); + this.viewport.applyConstraints(); + } + } + /** + * Raised when a double mouse press/release or touch/remove occurs on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-double-click + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Boolean} shift - True if the shift key was pressed during this event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-double-click', { + tracker: event.eventSource, + position: event.position, + shift: event.shift, + originalEvent: event.originalEvent + }); +} + +function onCanvasDrag( event ) { + var gestureSettings; + + var canvasDragEventArgs = { + tracker: event.eventSource, + position: event.position, + delta: event.delta, + speed: event.speed, + direction: event.direction, + shift: event.shift, + originalEvent: event.originalEvent, + preventDefaultAction: event.preventDefaultAction + }; + + /** + * Raised when a mouse or touch drag operation occurs on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-drag + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {OpenSeadragon.Point} delta - The x,y components of the difference between start drag and end drag. + * @property {Number} speed - Current computed speed, in pixels per second. + * @property {Number} direction - Current computed direction, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0. + * @property {Boolean} shift - True if the shift key was pressed during this event. + * @property {Object} originalEvent - The original DOM event. + * @property {Boolean} preventDefaultAction - Set to true to prevent default drag behaviour. Default: false. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-drag', canvasDragEventArgs); + + if ( !canvasDragEventArgs.preventDefaultAction && this.viewport ) { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); + if( !this.panHorizontal ){ + event.delta.x = 0; + } + if( !this.panVertical ){ + event.delta.y = 0; + } + + if( this.constrainDuringPan ){ + var delta = this.viewport.deltaPointsFromPixels( event.delta.negate() ); + + this.viewport.centerSpringX.target.value += delta.x; + this.viewport.centerSpringY.target.value += delta.y; + + var bounds = this.viewport.getBounds(); + var constrainedBounds = this.viewport.getConstrainedBounds(); + + this.viewport.centerSpringX.target.value -= delta.x; + this.viewport.centerSpringY.target.value -= delta.y; + + if (bounds.x != constrainedBounds.x) { + event.delta.x = 0; + } + + if (bounds.y != constrainedBounds.y) { + event.delta.y = 0; + } + } + + this.viewport.panBy( this.viewport.deltaPointsFromPixels( event.delta.negate() ), gestureSettings.flickEnabled && !this.constrainDuringPan); + } +} + +function onCanvasDragEnd( event ) { + if (!event.preventDefaultAction && this.viewport) { + var gestureSettings = this.gestureSettingsByDeviceType(event.pointerType); + if (gestureSettings.flickEnabled && + event.speed >= gestureSettings.flickMinSpeed) { + var amplitudeX = 0; + if (this.panHorizontal) { + amplitudeX = gestureSettings.flickMomentum * event.speed * + Math.cos(event.direction); + } + var amplitudeY = 0; + if (this.panVertical) { + amplitudeY = gestureSettings.flickMomentum * event.speed * + Math.sin(event.direction); + } + var center = this.viewport.pixelFromPoint( + this.viewport.getCenter(true)); + var target = this.viewport.pointFromPixel( + new $.Point(center.x - amplitudeX, center.y - amplitudeY)); + this.viewport.panTo(target, false); + } + this.viewport.applyConstraints(); + } + /** + * Raised when a mouse or touch drag operation ends on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-drag-end + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} speed - Speed at the end of a drag gesture, in pixels per second. + * @property {Number} direction - Direction at the end of a drag gesture, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0. + * @property {Boolean} shift - True if the shift key was pressed during this event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('canvas-drag-end', { + tracker: event.eventSource, + position: event.position, + speed: event.speed, + direction: event.direction, + shift: event.shift, + originalEvent: event.originalEvent + }); +} + +function onCanvasEnter( event ) { + /** + * Raised when a pointer enters the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-enter + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {String} pointerType - "mouse", "touch", "pen", etc. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Number} pointers - Number of pointers (all types) active in the tracked element. + * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-enter', { + tracker: event.eventSource, + pointerType: event.pointerType, + position: event.position, + buttons: event.buttons, + pointers: event.pointers, + insideElementPressed: event.insideElementPressed, + buttonDownAny: event.buttonDownAny, + originalEvent: event.originalEvent + }); +} + +function onCanvasExit( event ) { + + if (window.location != window.parent.location){ + $.MouseTracker.resetAllMouseTrackers(); + } + + /** + * Raised when a pointer leaves the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-exit + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {String} pointerType - "mouse", "touch", "pen", etc. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Number} pointers - Number of pointers (all types) active in the tracked element. + * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-exit', { + tracker: event.eventSource, + pointerType: event.pointerType, + position: event.position, + buttons: event.buttons, + pointers: event.pointers, + insideElementPressed: event.insideElementPressed, + buttonDownAny: event.buttonDownAny, + originalEvent: event.originalEvent + }); +} + +function onCanvasPress( event ) { + /** + * Raised when the primary mouse button is pressed or touch starts on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-press + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {String} pointerType - "mouse", "touch", "pen", etc. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * @property {Boolean} insideElementReleased - True if the cursor still inside the tracked element when the button was released. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-press', { + tracker: event.eventSource, + pointerType: event.pointerType, + position: event.position, + insideElementPressed: event.insideElementPressed, + insideElementReleased: event.insideElementReleased, + originalEvent: event.originalEvent + }); +} + +function onCanvasRelease( event ) { + /** + * Raised when the primary mouse button is released or touch ends on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-release + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {String} pointerType - "mouse", "touch", "pen", etc. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * @property {Boolean} insideElementReleased - True if the cursor still inside the tracked element when the button was released. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-release', { + tracker: event.eventSource, + pointerType: event.pointerType, + position: event.position, + insideElementPressed: event.insideElementPressed, + insideElementReleased: event.insideElementReleased, + originalEvent: event.originalEvent + }); +} + +function onCanvasNonPrimaryPress( event ) { + /** + * Raised when any non-primary pointer button is pressed on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-nonprimary-press + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {String} pointerType - "mouse", "touch", "pen", etc. + * @property {Number} button - Button which caused the event. + * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. + * @property {Number} buttons - Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-nonprimary-press', { + tracker: event.eventSource, + position: event.position, + pointerType: event.pointerType, + button: event.button, + buttons: event.buttons, + originalEvent: event.originalEvent + }); +} + +function onCanvasNonPrimaryRelease( event ) { + /** + * Raised when any non-primary pointer button is released on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-nonprimary-release + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {String} pointerType - "mouse", "touch", "pen", etc. + * @property {Number} button - Button which caused the event. + * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. + * @property {Number} buttons - Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-nonprimary-release', { + tracker: event.eventSource, + position: event.position, + pointerType: event.pointerType, + button: event.button, + buttons: event.buttons, + originalEvent: event.originalEvent + }); +} + +function onCanvasPinch( event ) { + var gestureSettings, + centerPt, + lastCenterPt, + panByPt; + + if ( !event.preventDefaultAction && this.viewport ) { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); + if ( gestureSettings.pinchToZoom ) { + centerPt = this.viewport.pointFromPixel( event.center, true ); + lastCenterPt = this.viewport.pointFromPixel( event.lastCenter, true ); + panByPt = lastCenterPt.minus( centerPt ); + if( !this.panHorizontal ) { + panByPt.x = 0; + } + if( !this.panVertical ) { + panByPt.y = 0; + } + this.viewport.zoomBy( event.distance / event.lastDistance, centerPt, true ); + this.viewport.panBy( panByPt, true ); + this.viewport.applyConstraints(); + } + if ( gestureSettings.pinchRotate ) { + // Pinch rotate + var angle1 = Math.atan2(event.gesturePoints[0].currentPos.y - event.gesturePoints[1].currentPos.y, + event.gesturePoints[0].currentPos.x - event.gesturePoints[1].currentPos.x); + var angle2 = Math.atan2(event.gesturePoints[0].lastPos.y - event.gesturePoints[1].lastPos.y, + event.gesturePoints[0].lastPos.x - event.gesturePoints[1].lastPos.x); + this.viewport.setRotation(this.viewport.getRotation() + ((angle1 - angle2) * (180 / Math.PI))); + } + } + /** + * Raised when a pinch event occurs on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-pinch + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {Array.} gesturePoints - Gesture points associated with the gesture. Velocity data can be found here. + * @property {OpenSeadragon.Point} lastCenter - The previous center point of the two pinch contact points relative to the tracked element. + * @property {OpenSeadragon.Point} center - The center point of the two pinch contact points relative to the tracked element. + * @property {Number} lastDistance - The previous distance between the two pinch contact points in CSS pixels. + * @property {Number} distance - The distance between the two pinch contact points in CSS pixels. + * @property {Boolean} shift - True if the shift key was pressed during this event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('canvas-pinch', { + tracker: event.eventSource, + gesturePoints: event.gesturePoints, + lastCenter: event.lastCenter, + center: event.center, + lastDistance: event.lastDistance, + distance: event.distance, + shift: event.shift, + originalEvent: event.originalEvent + }); + //cancels event + return false; +} + +function onCanvasScroll( event ) { + var gestureSettings, + factor, + thisScrollTime, + deltaScrollTime; + + /* Certain scroll devices fire the scroll event way too fast so we are injecting a simple adjustment to keep things + * partially normalized. If we have already fired an event within the last 'minScrollDelta' milliseconds we skip + * this one and wait for the next event. */ + thisScrollTime = $.now(); + deltaScrollTime = thisScrollTime - this._lastScrollTime; + if (deltaScrollTime > this.minScrollDeltaTime) { + this._lastScrollTime = thisScrollTime; + + if ( !event.preventDefaultAction && this.viewport ) { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); + if ( gestureSettings.scrollToZoom ) { + factor = Math.pow( this.zoomPerScroll, event.scroll ); + this.viewport.zoomBy( + factor, + this.viewport.pointFromPixel( event.position, true ) + ); + this.viewport.applyConstraints(); + } + } + /** + * Raised when a scroll event occurs on the {@link OpenSeadragon.Viewer#canvas} element (mouse wheel). + * + * @event canvas-scroll + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} scroll - The scroll delta for the event. + * @property {Boolean} shift - True if the shift key was pressed during this event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-scroll', { + tracker: event.eventSource, + position: event.position, + scroll: event.scroll, + shift: event.shift, + originalEvent: event.originalEvent + }); + if (gestureSettings && gestureSettings.scrollToZoom) { + //cancels event + return false; + } + } + else { + gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); + if (gestureSettings && gestureSettings.scrollToZoom) { + return false; // We are swallowing this event + } + } +} + +function onContainerEnter( event ) { + THIS[ this.hash ].mouseInside = true; + abortControlsAutoHide( this ); + /** + * Raised when the cursor enters the {@link OpenSeadragon.Viewer#container} element. + * + * @event container-enter + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Number} pointers - Number of pointers (all types) active in the tracked element. + * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'container-enter', { + tracker: event.eventSource, + position: event.position, + buttons: event.buttons, + pointers: event.pointers, + insideElementPressed: event.insideElementPressed, + buttonDownAny: event.buttonDownAny, + originalEvent: event.originalEvent + }); +} + +function onContainerExit( event ) { + if ( event.pointers < 1 ) { + THIS[ this.hash ].mouseInside = false; + if ( !THIS[ this.hash ].animating ) { + beginControlsAutoHide( this ); + } + } + /** + * Raised when the cursor leaves the {@link OpenSeadragon.Viewer#container} element. + * + * @event container-exit + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Number} pointers - Number of pointers (all types) active in the tracked element. + * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'container-exit', { + tracker: event.eventSource, + position: event.position, + buttons: event.buttons, + pointers: event.pointers, + insideElementPressed: event.insideElementPressed, + buttonDownAny: event.buttonDownAny, + originalEvent: event.originalEvent + }); +} + + +/////////////////////////////////////////////////////////////////////////////// +// Page update routines ( aka Views - for future reference ) +/////////////////////////////////////////////////////////////////////////////// + +function updateMulti( viewer ) { + updateOnce( viewer ); + + // Request the next frame, unless we've been closed + if ( viewer.isOpen() ) { + viewer._updateRequestId = scheduleUpdate( viewer, updateMulti ); + } else { + viewer._updateRequestId = false; + } +} + +function updateOnce( viewer ) { + + //viewer.profiler.beginUpdate(); + + if (viewer._opening) { + return; + } + + if (viewer.autoResize) { + var containerSize = _getSafeElemSize(viewer.container); + var prevContainerSize = THIS[viewer.hash].prevContainerSize; + if (!containerSize.equals(prevContainerSize)) { + var viewport = viewer.viewport; + if (viewer.preserveImageSizeOnResize) { + var resizeRatio = prevContainerSize.x / containerSize.x; + var zoom = viewport.getZoom() * resizeRatio; + var center = viewport.getCenter(); + viewport.resize(containerSize, false); + viewport.zoomTo(zoom, null, true); + viewport.panTo(center, true); + } else { + // maintain image position + var oldBounds = viewport.getBounds(); + viewport.resize(containerSize, true); + viewport.fitBoundsWithConstraints(oldBounds, true); + } + THIS[viewer.hash].prevContainerSize = containerSize; + THIS[viewer.hash].forceRedraw = true; + } + } + + var viewportChange = viewer.viewport.update(); + var animated = viewer.world.update() || viewportChange; + + if (viewportChange) { + /** + * Raised when any spring animation update occurs (zoom, pan, etc.), + * before the viewer has drawn the new location. + * + * @event viewport-change + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + viewer.raiseEvent('viewport-change'); + } + + if( viewer.referenceStrip ){ + animated = viewer.referenceStrip.update( viewer.viewport ) || animated; + } + + if ( !THIS[ viewer.hash ].animating && animated ) { + /** + * Raised when any spring animation starts (zoom, pan, etc.). + * + * @event animation-start + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + viewer.raiseEvent( "animation-start" ); + abortControlsAutoHide( viewer ); + } + + if ( animated || THIS[ viewer.hash ].forceRedraw || viewer.world.needsDraw() ) { + drawWorld( viewer ); + viewer._drawOverlays(); + if( viewer.navigator ){ + viewer.navigator.update( viewer.viewport ); + } + + THIS[ viewer.hash ].forceRedraw = false; + + if (animated) { + /** + * Raised when any spring animation update occurs (zoom, pan, etc.), + * after the viewer has drawn the new location. + * + * @event animation + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + viewer.raiseEvent( "animation" ); + } + } + + if ( THIS[ viewer.hash ].animating && !animated ) { + /** + * Raised when any spring animation ends (zoom, pan, etc.). + * + * @event animation-finish + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + viewer.raiseEvent( "animation-finish" ); + + if ( !THIS[ viewer.hash ].mouseInside ) { + beginControlsAutoHide( viewer ); + } + } + + THIS[ viewer.hash ].animating = animated; + + //viewer.profiler.endUpdate(); +} + +function drawWorld( viewer ) { + viewer.imageLoader.clear(); + viewer.drawer.clear(); + viewer.world.draw(); + + /** + * - Needs documentation - + * + * @event update-viewport + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + viewer.raiseEvent( 'update-viewport', {} ); +} + +/////////////////////////////////////////////////////////////////////////////// +// Navigation Controls +/////////////////////////////////////////////////////////////////////////////// +function resolveUrl( prefix, url ) { + return prefix ? prefix + url : url; +} + + + +function beginZoomingIn() { + THIS[ this.hash ].lastZoomTime = $.now(); + THIS[ this.hash ].zoomFactor = this.zoomPerSecond; + THIS[ this.hash ].zooming = true; + scheduleZoom( this ); +} + + +function beginZoomingOut() { + THIS[ this.hash ].lastZoomTime = $.now(); + THIS[ this.hash ].zoomFactor = 1.0 / this.zoomPerSecond; + THIS[ this.hash ].zooming = true; + scheduleZoom( this ); +} + + +function endZooming() { + THIS[ this.hash ].zooming = false; +} + + +function scheduleZoom( viewer ) { + $.requestAnimationFrame( $.delegate( viewer, doZoom ) ); +} + + +function doZoom() { + var currentTime, + deltaTime, + adjustedFactor; + + if ( THIS[ this.hash ].zooming && this.viewport) { + currentTime = $.now(); + deltaTime = currentTime - THIS[ this.hash ].lastZoomTime; + adjustedFactor = Math.pow( THIS[ this.hash ].zoomFactor, deltaTime / 1000 ); + + this.viewport.zoomBy( adjustedFactor ); + this.viewport.applyConstraints(); + THIS[ this.hash ].lastZoomTime = currentTime; + scheduleZoom( this ); + } +} + + +function doSingleZoomIn() { + if ( this.viewport ) { + THIS[ this.hash ].zooming = false; + this.viewport.zoomBy( + this.zoomPerClick / 1.0 + ); + this.viewport.applyConstraints(); + } +} + + +function doSingleZoomOut() { + if ( this.viewport ) { + THIS[ this.hash ].zooming = false; + this.viewport.zoomBy( + 1.0 / this.zoomPerClick + ); + this.viewport.applyConstraints(); + } +} + + +function lightUp() { + this.buttons.emulateEnter(); + this.buttons.emulateExit(); +} + + +function onHome() { + if ( this.viewport ) { + this.viewport.goHome(); + } +} + + +function onFullScreen() { + if ( this.isFullPage() && !$.isFullScreen() ) { + // Is fullPage but not fullScreen + this.setFullPage( false ); + } else { + this.setFullScreen( !this.isFullPage() ); + } + // correct for no mouseout event on change + if ( this.buttons ) { + this.buttons.emulateExit(); + } + this.fullPageButton.element.focus(); + if ( this.viewport ) { + this.viewport.applyConstraints(); + } +} + +/** + * Note: The current rotation feature is limited to 90 degree turns. + */ +function onRotateLeft() { + if ( this.viewport ) { + var currRotation = this.viewport.getRotation(); + if (currRotation === 0) { + currRotation = 270; + } + else { + currRotation -= 90; + } + this.viewport.setRotation(currRotation); + } +} + +/** + * Note: The current rotation feature is limited to 90 degree turns. + */ +function onRotateRight() { + if ( this.viewport ) { + var currRotation = this.viewport.getRotation(); + if (currRotation === 270) { + currRotation = 0; + } + else { + currRotation += 90; + } + this.viewport.setRotation(currRotation); + } +} + + +function onPrevious(){ + var previous = this._sequenceIndex - 1; + if(this.navPrevNextWrap && previous < 0){ + previous += this.tileSources.length; + } + this.goToPage( previous ); +} + + +function onNext(){ + var next = this._sequenceIndex + 1; + if(this.navPrevNextWrap && next >= this.tileSources.length){ + next = 0; + } + this.goToPage( next ); +} + + +}( OpenSeadragon )); + +/* + * OpenSeadragon - Navigator + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class Navigator + * @classdesc The Navigator provides a small view of the current image as fixed + * while representing the viewport as a moving box serving as a frame + * of reference in the larger viewport as to which portion of the image + * is currently being examined. The navigator's viewport can be interacted + * with using the keyboard or the mouse. + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.Viewer + * @extends OpenSeadragon.EventSource + * @param {Object} options + */ +$.Navigator = function( options ){ + + var viewer = options.viewer, + _this = this, + viewerSize, + navigatorSize; + + //We may need to create a new element and id if they did not + //provide the id for the existing element + if( !options.id ){ + options.id = 'navigator-' + $.now(); + this.element = $.makeNeutralElement( "div" ); + options.controlOptions = { + anchor: $.ControlAnchor.TOP_RIGHT, + attachToViewer: true, + autoFade: options.autoFade + }; + + if( options.position ){ + if( 'BOTTOM_RIGHT' == options.position ){ + options.controlOptions.anchor = $.ControlAnchor.BOTTOM_RIGHT; + } else if( 'BOTTOM_LEFT' == options.position ){ + options.controlOptions.anchor = $.ControlAnchor.BOTTOM_LEFT; + } else if( 'TOP_RIGHT' == options.position ){ + options.controlOptions.anchor = $.ControlAnchor.TOP_RIGHT; + } else if( 'TOP_LEFT' == options.position ){ + options.controlOptions.anchor = $.ControlAnchor.TOP_LEFT; + } else if( 'ABSOLUTE' == options.position ){ + options.controlOptions.anchor = $.ControlAnchor.ABSOLUTE; + options.controlOptions.top = options.top; + options.controlOptions.left = options.left; + options.controlOptions.height = options.height; + options.controlOptions.width = options.width; + } + } + + } else { + this.element = document.getElementById( options.id ); + options.controlOptions = { + anchor: $.ControlAnchor.NONE, + attachToViewer: false, + autoFade: false + }; + } + this.element.id = options.id; + this.element.className += ' navigator'; + + options = $.extend( true, { + sizeRatio: $.DEFAULT_SETTINGS.navigatorSizeRatio + }, options, { + element: this.element, + tabIndex: -1, // No keyboard navigation, omit from tab order + //These need to be overridden to prevent recursion since + //the navigator is a viewer and a viewer has a navigator + showNavigator: false, + mouseNavEnabled: false, + showNavigationControl: false, + showSequenceControl: false, + immediateRender: true, + blendTime: 0, + animationTime: 0, + autoResize: options.autoResize, + // prevent resizing the navigator from adding unwanted space around the image + minZoomImageRatio: 1.0 + }); + + options.minPixelRatio = this.minPixelRatio = viewer.minPixelRatio; + + $.setElementTouchActionNone( this.element ); + + this.borderWidth = 2; + //At some browser magnification levels the display regions lines up correctly, but at some there appears to + //be a one pixel gap. + this.fudge = new $.Point(1, 1); + this.totalBorderWidths = new $.Point(this.borderWidth * 2, this.borderWidth * 2).minus(this.fudge); + + + if ( options.controlOptions.anchor != $.ControlAnchor.NONE ) { + (function( style, borderWidth ){ + style.margin = '0px'; + style.border = borderWidth + 'px solid #555'; + style.padding = '0px'; + style.background = '#000'; + style.opacity = 0.8; + style.overflow = 'hidden'; + }( this.element.style, this.borderWidth)); + } + + this.displayRegion = $.makeNeutralElement( "div" ); + this.displayRegion.id = this.element.id + '-displayregion'; + this.displayRegion.className = 'displayregion'; + + (function( style, borderWidth ){ + style.position = 'relative'; + style.top = '0px'; + style.left = '0px'; + style.fontSize = '0px'; + style.overflow = 'hidden'; + style.border = borderWidth + 'px solid #900'; + style.margin = '0px'; + style.padding = '0px'; + //TODO: IE doesnt like this property being set + //try{ style.outline = '2px auto #909'; }catch(e){/*ignore*/} + + style.background = 'transparent'; + + // We use square bracket notation on the statement below, because float is a keyword. + // This is important for the Google Closure compiler, if nothing else. + /*jshint sub:true */ + style['float'] = 'left'; //Webkit + + style.cssFloat = 'left'; //Firefox + style.styleFloat = 'left'; //IE + style.zIndex = 999999999; + style.cursor = 'default'; + }( this.displayRegion.style, this.borderWidth )); + + this.displayRegionContainer = $.makeNeutralElement("div"); + this.displayRegionContainer.id = this.element.id + '-displayregioncontainer'; + this.displayRegionContainer.className = "displayregioncontainer"; + this.displayRegionContainer.style.width = "100%"; + this.displayRegionContainer.style.height = "100%"; + + viewer.addControl( + this.element, + options.controlOptions + ); + + this._resizeWithViewer = options.controlOptions.anchor != $.ControlAnchor.ABSOLUTE && + options.controlOptions.anchor != $.ControlAnchor.NONE; + + if ( this._resizeWithViewer ) { + if ( options.width && options.height ) { + this.element.style.height = typeof (options.height) == "number" ? (options.height + 'px') : options.height; + this.element.style.width = typeof (options.width) == "number" ? (options.width + 'px') : options.width; + } else { + viewerSize = $.getElementSize( viewer.element ); + this.element.style.height = Math.round( viewerSize.y * options.sizeRatio ) + 'px'; + this.element.style.width = Math.round( viewerSize.x * options.sizeRatio ) + 'px'; + this.oldViewerSize = viewerSize; + } + navigatorSize = $.getElementSize( this.element ); + this.elementArea = navigatorSize.x * navigatorSize.y; + } + + this.oldContainerSize = new $.Point( 0, 0 ); + + $.Viewer.apply( this, [ options ] ); + + this.displayRegionContainer.appendChild(this.displayRegion); + this.element.getElementsByTagName('div')[0].appendChild(this.displayRegionContainer); + + function rotate(degrees) { + _setTransformRotate(_this.displayRegionContainer, degrees); + _setTransformRotate(_this.displayRegion, -degrees); + _this.viewport.setRotation(degrees); + } + if (options.navigatorRotate) { + var degrees = options.viewer.viewport ? + options.viewer.viewport.getRotation() : + options.viewer.degrees || 0; + rotate(degrees); + options.viewer.addHandler("rotate", function (args) { + rotate(args.degrees); + }); + } + + // Remove the base class' (Viewer's) innerTracker and replace it with our own + this.innerTracker.destroy(); + this.innerTracker = new $.MouseTracker({ + element: this.element, + dragHandler: $.delegate( this, onCanvasDrag ), + clickHandler: $.delegate( this, onCanvasClick ), + releaseHandler: $.delegate( this, onCanvasRelease ), + scrollHandler: $.delegate( this, onCanvasScroll ) + }); + + this.addHandler("reset-size", function() { + if (_this.viewport) { + _this.viewport.goHome(true); + } + }); + + viewer.world.addHandler("item-index-change", function(event) { + window.setTimeout(function(){ + var item = _this.world.getItemAt(event.previousIndex); + _this.world.setItemIndex(item, event.newIndex); + }, 1); + }); + + viewer.world.addHandler("remove-item", function(event) { + var theirItem = event.item; + var myItem = _this._getMatchingItem(theirItem); + if (myItem) { + _this.world.removeItem(myItem); + } + }); + + this.update(viewer.viewport); +}; + +$.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.Navigator.prototype */{ + + /** + * Used to notify the navigator when its size has changed. + * Especially useful when {@link OpenSeadragon.Options}.navigatorAutoResize is set to false and the navigator is resizable. + * @function + */ + updateSize: function () { + if ( this.viewport ) { + var containerSize = new $.Point( + (this.container.clientWidth === 0 ? 1 : this.container.clientWidth), + (this.container.clientHeight === 0 ? 1 : this.container.clientHeight) + ); + + if ( !containerSize.equals( this.oldContainerSize ) ) { + this.viewport.resize( containerSize, true ); + this.viewport.goHome(true); + this.oldContainerSize = containerSize; + this.drawer.clear(); + this.world.draw(); + } + } + }, + + /** + * Used to update the navigator minimap's viewport rectangle when a change in the viewer's viewport occurs. + * @function + * @param {OpenSeadragon.Viewport} The viewport this navigator is tracking. + */ + update: function( viewport ) { + + var viewerSize, + newWidth, + newHeight, + bounds, + topleft, + bottomright; + + viewerSize = $.getElementSize( this.viewer.element ); + if ( this._resizeWithViewer && viewerSize.x && viewerSize.y && !viewerSize.equals( this.oldViewerSize ) ) { + this.oldViewerSize = viewerSize; + + if ( this.maintainSizeRatio || !this.elementArea) { + newWidth = viewerSize.x * this.sizeRatio; + newHeight = viewerSize.y * this.sizeRatio; + } else { + newWidth = Math.sqrt(this.elementArea * (viewerSize.x / viewerSize.y)); + newHeight = this.elementArea / newWidth; + } + + this.element.style.width = Math.round( newWidth ) + 'px'; + this.element.style.height = Math.round( newHeight ) + 'px'; + + if (!this.elementArea) { + this.elementArea = newWidth * newHeight; + } + + this.updateSize(); + } + + if (viewport && this.viewport) { + bounds = viewport.getBoundsNoRotate(true); + topleft = this.viewport.pixelFromPointNoRotate(bounds.getTopLeft(), false); + bottomright = this.viewport.pixelFromPointNoRotate(bounds.getBottomRight(), false) + .minus( this.totalBorderWidths ); + + //update style for navigator-box + var style = this.displayRegion.style; + style.display = this.world.getItemCount() ? 'block' : 'none'; + + style.top = Math.round( topleft.y ) + 'px'; + style.left = Math.round( topleft.x ) + 'px'; + + var width = Math.abs( topleft.x - bottomright.x ); + var height = Math.abs( topleft.y - bottomright.y ); + // make sure width and height are non-negative so IE doesn't throw + style.width = Math.round( Math.max( width, 0 ) ) + 'px'; + style.height = Math.round( Math.max( height, 0 ) ) + 'px'; + } + + }, + + // overrides Viewer.addTiledImage + addTiledImage: function(options) { + var _this = this; + + var original = options.originalTiledImage; + delete options.original; + + var optionsClone = $.extend({}, options, { + success: function(event) { + var myItem = event.item; + myItem._originalForNavigator = original; + _this._matchBounds(myItem, original, true); + + function matchBounds() { + _this._matchBounds(myItem, original); + } + + function matchOpacity() { + _this._matchOpacity(myItem, original); + } + + function matchCompositeOperation() { + _this._matchCompositeOperation(myItem, original); + } + + original.addHandler('bounds-change', matchBounds); + original.addHandler('clip-change', matchBounds); + original.addHandler('opacity-change', matchOpacity); + original.addHandler('composite-operation-change', matchCompositeOperation); + } + }); + + return $.Viewer.prototype.addTiledImage.apply(this, [optionsClone]); + }, + + // private + _getMatchingItem: function(theirItem) { + var count = this.world.getItemCount(); + var item; + for (var i = 0; i < count; i++) { + item = this.world.getItemAt(i); + if (item._originalForNavigator === theirItem) { + return item; + } + } + + return null; + }, + + // private + _matchBounds: function(myItem, theirItem, immediately) { + var bounds = theirItem.getBoundsNoRotate(); + myItem.setPosition(bounds.getTopLeft(), immediately); + myItem.setWidth(bounds.width, immediately); + myItem.setRotation(theirItem.getRotation(), immediately); + myItem.setClip(theirItem.getClip()); + }, + + // private + _matchOpacity: function(myItem, theirItem) { + myItem.setOpacity(theirItem.opacity); + }, + + // private + _matchCompositeOperation: function(myItem, theirItem) { + myItem.setCompositeOperation(theirItem.compositeOperation); + } +}); + +/** + * @private + * @inner + * @function + */ +function onCanvasClick( event ) { + if ( event.quick && this.viewer.viewport ) { + this.viewer.viewport.panTo(this.viewport.pointFromPixel(event.position)); + this.viewer.viewport.applyConstraints(); + } +} + +/** + * @private + * @inner + * @function + */ +function onCanvasDrag( event ) { + if ( this.viewer.viewport ) { + if( !this.panHorizontal ){ + event.delta.x = 0; + } + if( !this.panVertical ){ + event.delta.y = 0; + } + this.viewer.viewport.panBy( + this.viewport.deltaPointsFromPixels( + event.delta + ) + ); + if( this.viewer.constrainDuringPan ){ + this.viewer.viewport.applyConstraints(); + } + } +} + + +/** + * @private + * @inner + * @function + */ +function onCanvasRelease( event ) { + if ( event.insideElementPressed && this.viewer.viewport ) { + this.viewer.viewport.applyConstraints(); + } +} + + +/** + * @private + * @inner + * @function + */ +function onCanvasScroll( event ) { + /** + * Raised when a scroll event occurs on the {@link OpenSeadragon.Viewer#navigator} element (mouse wheel, touch pinch, etc.). + * + * @event navigator-scroll + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} scroll - The scroll delta for the event. + * @property {Boolean} shift - True if the shift key was pressed during this event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.viewer.raiseEvent( 'navigator-scroll', { + tracker: event.eventSource, + position: event.position, + scroll: event.scroll, + shift: event.shift, + originalEvent: event.originalEvent + }); + + //dont scroll the page up and down if the user is scrolling + //in the navigator + return false; +} + +/** + * @function + * @private + * @param {Object} element + * @param {Number} degrees + */ +function _setTransformRotate (element, degrees) { + element.style.webkitTransform = "rotate(" + degrees + "deg)"; + element.style.mozTransform = "rotate(" + degrees + "deg)"; + element.style.msTransform = "rotate(" + degrees + "deg)"; + element.style.oTransform = "rotate(" + degrees + "deg)"; + element.style.transform = "rotate(" + degrees + "deg)"; +} + +}( OpenSeadragon )); + +/* + * OpenSeadragon - getString/setString + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +//TODO: I guess this is where the i18n needs to be reimplemented. I'll look +// into existing patterns for i18n in javascript but i think that mimicking +// pythons gettext might be a reasonable approach. +var I18N = { + Errors: { + Dzc: "Sorry, we don't support Deep Zoom Collections!", + Dzi: "Hmm, this doesn't appear to be a valid Deep Zoom Image.", + Xml: "Hmm, this doesn't appear to be a valid Deep Zoom Image.", + ImageFormat: "Sorry, we don't support {0}-based Deep Zoom Images.", + Security: "It looks like a security restriction stopped us from " + + "loading this Deep Zoom Image.", + Status: "This space unintentionally left blank ({0} {1}).", + OpenFailed: "Unable to open {0}: {1}" + }, + + Tooltips: { + FullPage: "Toggle full page", + Home: "Go home", + ZoomIn: "Zoom in", + ZoomOut: "Zoom out", + NextPage: "Next page", + PreviousPage: "Previous page", + RotateLeft: "Rotate left", + RotateRight: "Rotate right" + } +}; + +$.extend( $, /** @lends OpenSeadragon */{ + + /** + * @function + * @param {String} property + */ + getString: function( prop ) { + + var props = prop.split('.'), + string = null, + args = arguments, + container = I18N, + i; + + for (i = 0; i < props.length - 1; i++) { + // in case not a subproperty + container = container[ props[ i ] ] || {}; + } + string = container[ props[ i ] ]; + + if ( typeof( string ) != "string" ) { + $.console.log( "Untranslated source string:", prop ); + string = ""; // FIXME: this breaks gettext()-style convention, which would return source + } + + return string.replace(/\{\d+\}/g, function(capture) { + var i = parseInt( capture.match( /\d+/ ), 10 ) + 1; + return i < args.length ? + args[ i ] : + ""; + }); + }, + + /** + * @function + * @param {String} property + * @param {*} value + */ + setString: function( prop, value ) { + + var props = prop.split('.'), + container = I18N, + i; + + for ( i = 0; i < props.length - 1; i++ ) { + if ( !container[ props[ i ] ] ) { + container[ props[ i ] ] = {}; + } + container = container[ props[ i ] ]; + } + + container[ props[ i ] ] = value; + } + +}); + +}( OpenSeadragon )); + +/* + * OpenSeadragon - Point + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class Point + * @classdesc A Point is really used as a 2-dimensional vector, equally useful for + * representing a point on a plane, or the height and width of a plane + * not requiring any other frame of reference. + * + * @memberof OpenSeadragon + * @param {Number} [x] The vector component 'x'. Defaults to the origin at 0. + * @param {Number} [y] The vector component 'y'. Defaults to the origin at 0. + */ +$.Point = function( x, y ) { + /** + * The vector component 'x'. + * @member {Number} x + * @memberof OpenSeadragon.Point# + */ + this.x = typeof ( x ) == "number" ? x : 0; + /** + * The vector component 'y'. + * @member {Number} y + * @memberof OpenSeadragon.Point# + */ + this.y = typeof ( y ) == "number" ? y : 0; +}; + +/** @lends OpenSeadragon.Point.prototype */ +$.Point.prototype = { + /** + * @function + * @returns {OpenSeadragon.Point} a duplicate of this Point + */ + clone: function() { + return new $.Point(this.x, this.y); + }, + + /** + * Add another Point to this point and return a new Point. + * @function + * @param {OpenSeadragon.Point} point The point to add vector components. + * @returns {OpenSeadragon.Point} A new point representing the sum of the + * vector components + */ + plus: function( point ) { + return new $.Point( + this.x + point.x, + this.y + point.y + ); + }, + + /** + * Substract another Point to this point and return a new Point. + * @function + * @param {OpenSeadragon.Point} point The point to substract vector components. + * @returns {OpenSeadragon.Point} A new point representing the substraction of the + * vector components + */ + minus: function( point ) { + return new $.Point( + this.x - point.x, + this.y - point.y + ); + }, + + /** + * Multiply this point by a factor and return a new Point. + * @function + * @param {Number} factor The factor to multiply vector components. + * @returns {OpenSeadragon.Point} A new point representing the multiplication + * of the vector components by the factor + */ + times: function( factor ) { + return new $.Point( + this.x * factor, + this.y * factor + ); + }, + + /** + * Divide this point by a factor and return a new Point. + * @function + * @param {Number} factor The factor to divide vector components. + * @returns {OpenSeadragon.Point} A new point representing the division of the + * vector components by the factor + */ + divide: function( factor ) { + return new $.Point( + this.x / factor, + this.y / factor + ); + }, + + /** + * Compute the opposite of this point and return a new Point. + * @function + * @returns {OpenSeadragon.Point} A new point representing the opposite of the + * vector components + */ + negate: function() { + return new $.Point( -this.x, -this.y ); + }, + + /** + * Compute the distance between this point and another point. + * @function + * @param {OpenSeadragon.Point} point The point to compute the distance with. + * @returns {Number} The distance between the 2 points + */ + distanceTo: function( point ) { + return Math.sqrt( + Math.pow( this.x - point.x, 2 ) + + Math.pow( this.y - point.y, 2 ) + ); + }, + + /** + * Compute the squared distance between this point and another point. + * Useful for optimizing things like comparing distances. + * @function + * @param {OpenSeadragon.Point} point The point to compute the squared distance with. + * @returns {Number} The squared distance between the 2 points + */ + squaredDistanceTo: function( point ) { + return Math.pow( this.x - point.x, 2 ) + + Math.pow( this.y - point.y, 2 ); + }, + + /** + * Apply a function to each coordinate of this point and return a new point. + * @function + * @param {function} func The function to apply to each coordinate. + * @returns {OpenSeadragon.Point} A new point with the coordinates computed + * by the specified function + */ + apply: function( func ) { + return new $.Point( func( this.x ), func( this.y ) ); + }, + + /** + * Check if this point is equal to another one. + * @function + * @param {OpenSeadragon.Point} point The point to compare this point with. + * @returns {Boolean} true if they are equal, false otherwise. + */ + equals: function( point ) { + return ( + point instanceof $.Point + ) && ( + this.x === point.x + ) && ( + this.y === point.y + ); + }, + + /** + * Rotates the point around the specified pivot + * From http://stackoverflow.com/questions/4465931/rotate-rectangle-around-a-point + * @function + * @param {Number} degress to rotate around the pivot. + * @param {OpenSeadragon.Point} [pivot=(0,0)] Point around which to rotate. + * Defaults to the origin. + * @returns {OpenSeadragon.Point}. A new point representing the point rotated around the specified pivot + */ + rotate: function (degrees, pivot) { + pivot = pivot || new $.Point(0, 0); + var cos; + var sin; + // Avoid float computations when possible + if (degrees % 90 === 0) { + var d = $.positiveModulo(degrees, 360); + switch (d) { + case 0: + cos = 1; + sin = 0; + break; + case 90: + cos = 0; + sin = 1; + break; + case 180: + cos = -1; + sin = 0; + break; + case 270: + cos = 0; + sin = -1; + break; + } + } else { + var angle = degrees * Math.PI / 180.0; + cos = Math.cos(angle); + sin = Math.sin(angle); + } + var x = cos * (this.x - pivot.x) - sin * (this.y - pivot.y) + pivot.x; + var y = sin * (this.x - pivot.x) + cos * (this.y - pivot.y) + pivot.y; + return new $.Point(x, y); + }, + + /** + * Convert this point to a string in the format (x,y) where x and y are + * rounded to the nearest integer. + * @function + * @returns {String} A string representation of this point. + */ + toString: function() { + return "(" + (Math.round(this.x * 100) / 100) + "," + (Math.round(this.y * 100) / 100) + ")"; + } +}; + +}( OpenSeadragon )); + +/* + * OpenSeadragon - TileSource + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + + +/** + * @class TileSource + * @classdesc The TileSource contains the most basic implementation required to create a + * smooth transition between layers in an image pyramid. It has only a single key + * interface that must be implemented to complete its key functionality: + * 'getTileUrl'. It also has several optional interfaces that can be + * implemented if a new TileSource wishes to support configuration via a simple + * object or array ('configure') and if the tile source supports or requires + * configuration via retrieval of a document on the network ala AJAX or JSONP, + * ('getImageInfo'). + *
      + * By default the image pyramid is split into N layers where the image's longest + * side in M (in pixels), where N is the smallest integer which satisfies + * 2^(N+1) >= M. + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.EventSource + * @param {Object} options + * You can either specify a URL, or literally define the TileSource (by specifying + * width, height, tileSize, tileOverlap, minLevel, and maxLevel). For the former, + * the extending class is expected to implement 'getImageInfo' and 'configure'. + * For the latter, the construction is assumed to occur through + * the extending classes implementation of 'configure'. + * @param {String} [options.url] + * The URL for the data necessary for this TileSource. + * @param {String} [options.referenceStripThumbnailUrl] + * The URL for a thumbnail image to be used by the reference strip + * @param {Function} [options.success] + * A function to be called upon successful creation. + * @param {Boolean} [options.ajaxWithCredentials] + * If this TileSource needs to make an AJAX call, this specifies whether to set + * the XHR's withCredentials (for accessing secure data). + * @param {Object} [options.ajaxHeaders] + * A set of headers to include in AJAX requests. + * @param {Number} [options.width] + * Width of the source image at max resolution in pixels. + * @param {Number} [options.height] + * Height of the source image at max resolution in pixels. + * @param {Number} [options.tileSize] + * The size of the tiles to assumed to make up each pyramid layer in pixels. + * Tile size determines the point at which the image pyramid must be + * divided into a matrix of smaller images. + * Use options.tileWidth and options.tileHeight to support non-square tiles. + * @param {Number} [options.tileWidth] + * The width of the tiles to assumed to make up each pyramid layer in pixels. + * @param {Number} [options.tileHeight] + * The height of the tiles to assumed to make up each pyramid layer in pixels. + * @param {Number} [options.tileOverlap] + * The number of pixels each tile is expected to overlap touching tiles. + * @param {Number} [options.minLevel] + * The minimum level to attempt to load. + * @param {Number} [options.maxLevel] + * The maximum level to attempt to load. + */ +$.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLevel ) { + var _this = this; + + var args = arguments, + options, + i; + + if( $.isPlainObject( width ) ){ + options = width; + }else{ + options = { + width: args[0], + height: args[1], + tileSize: args[2], + tileOverlap: args[3], + minLevel: args[4], + maxLevel: args[5] + }; + } + + //Tile sources supply some events, namely 'ready' when they must be configured + //by asynchronously fetching their configuration data. + $.EventSource.call( this ); + + //we allow options to override anything we dont treat as + //required via idiomatic options or which is functionally + //set depending on the state of the readiness of this tile + //source + $.extend( true, this, options ); + + if (!this.success) { + //Any functions that are passed as arguments are bound to the ready callback + for ( i = 0; i < arguments.length; i++ ) { + if ( $.isFunction( arguments[ i ] ) ) { + this.success = arguments[ i ]; + //only one callback per constructor + break; + } + } + } + + if (this.success) { + this.addHandler( 'ready', function ( event ) { + _this.success( event ); + } ); + } + + /** + * Ratio of width to height + * @member {Number} aspectRatio + * @memberof OpenSeadragon.TileSource# + */ + /** + * Vector storing x and y dimensions ( width and height respectively ). + * @member {OpenSeadragon.Point} dimensions + * @memberof OpenSeadragon.TileSource# + */ + /** + * The overlap in pixels each tile shares with its adjacent neighbors. + * @member {Number} tileOverlap + * @memberof OpenSeadragon.TileSource# + */ + /** + * The minimum pyramid level this tile source supports or should attempt to load. + * @member {Number} minLevel + * @memberof OpenSeadragon.TileSource# + */ + /** + * The maximum pyramid level this tile source supports or should attempt to load. + * @member {Number} maxLevel + * @memberof OpenSeadragon.TileSource# + */ + /** + * + * @member {Boolean} ready + * @memberof OpenSeadragon.TileSource# + */ + + if( 'string' == $.type( arguments[ 0 ] ) ){ + this.url = arguments[0]; + } + + if (this.url) { + //in case the getImageInfo method is overriden and/or implies an + //async mechanism set some safe defaults first + this.aspectRatio = 1; + this.dimensions = new $.Point( 10, 10 ); + this._tileWidth = 0; + this._tileHeight = 0; + this.tileOverlap = 0; + this.minLevel = 0; + this.maxLevel = 0; + this.ready = false; + //configuration via url implies the extending class + //implements and 'configure' + this.getImageInfo( this.url ); + + } else { + + //explicit configuration via positional args in constructor + //or the more idiomatic 'options' object + this.ready = true; + this.aspectRatio = (options.width && options.height) ? + (options.width / options.height) : 1; + this.dimensions = new $.Point( options.width, options.height ); + + if ( this.tileSize ){ + this._tileWidth = this._tileHeight = this.tileSize; + delete this.tileSize; + } else { + if( this.tileWidth ){ + // We were passed tileWidth in options, but we want to rename it + // with a leading underscore to make clear that it is not safe to directly modify it + this._tileWidth = this.tileWidth; + delete this.tileWidth; + } else { + this._tileWidth = 0; + } + + if( this.tileHeight ){ + // See note above about renaming this.tileWidth + this._tileHeight = this.tileHeight; + delete this.tileHeight; + } else { + this._tileHeight = 0; + } + } + + this.tileOverlap = options.tileOverlap ? options.tileOverlap : 0; + this.minLevel = options.minLevel ? options.minLevel : 0; + this.maxLevel = ( undefined !== options.maxLevel && null !== options.maxLevel ) ? + options.maxLevel : ( + ( options.width && options.height ) ? Math.ceil( + Math.log( Math.max( options.width, options.height ) ) / + Math.log( 2 ) + ) : 0 + ); + if( this.success && $.isFunction( this.success ) ){ + this.success( this ); + } + } + + +}; + +/** @lends OpenSeadragon.TileSource.prototype */ +$.TileSource.prototype = { + + getTileSize: function( level ) { + $.console.error( + "[TileSource.getTileSize] is deprecated." + + "Use TileSource.getTileWidth() and TileSource.getTileHeight() instead" + ); + return this._tileWidth; + }, + + /** + * Return the tileWidth for a given level. + * Subclasses should override this if tileWidth can be different at different levels + * such as in IIIFTileSource. Code should use this function rather than reading + * from ._tileWidth directly. + * @function + * @param {Number} level + */ + getTileWidth: function( level ) { + if (!this._tileWidth) { + return this.getTileSize(level); + } + return this._tileWidth; + }, + + /** + * Return the tileHeight for a given level. + * Subclasses should override this if tileHeight can be different at different levels + * such as in IIIFTileSource. Code should use this function rather than reading + * from ._tileHeight directly. + * @function + * @param {Number} level + */ + getTileHeight: function( level ) { + if (!this._tileHeight) { + return this.getTileSize(level); + } + return this._tileHeight; + }, + + /** + * @function + * @param {Number} level + */ + getLevelScale: function( level ) { + + // see https://github.com/openseadragon/openseadragon/issues/22 + // we use the tilesources implementation of getLevelScale to generate + // a memoized re-implementation + var levelScaleCache = {}, + i; + for( i = 0; i <= this.maxLevel; i++ ){ + levelScaleCache[ i ] = 1 / Math.pow(2, this.maxLevel - i); + } + this.getLevelScale = function( _level ){ + return levelScaleCache[ _level ]; + }; + return this.getLevelScale( level ); + }, + + /** + * @function + * @param {Number} level + */ + getNumTiles: function( level ) { + var scale = this.getLevelScale( level ), + x = Math.ceil( scale * this.dimensions.x / this.getTileWidth(level) ), + y = Math.ceil( scale * this.dimensions.y / this.getTileHeight(level) ); + + return new $.Point( x, y ); + }, + + /** + * @function + * @param {Number} level + */ + getPixelRatio: function( level ) { + var imageSizeScaled = this.dimensions.times( this.getLevelScale( level ) ), + rx = 1.0 / imageSizeScaled.x, + ry = 1.0 / imageSizeScaled.y; + + return new $.Point(rx, ry); + }, + + + /** + * @function + * @returns {Number} The highest level in this tile source that can be contained in a single tile. + */ + getClosestLevel: function() { + var i, + tiles; + + for (i = this.minLevel + 1; i <= this.maxLevel; i++){ + tiles = this.getNumTiles(i); + if (tiles.x > 1 || tiles.y > 1) { + break; + } + } + + return i - 1; + }, + + /** + * @function + * @param {Number} level + * @param {OpenSeadragon.Point} point + */ + getTileAtPoint: function(level, point) { + var validPoint = point.x >= 0 && point.x <= 1 && + point.y >= 0 && point.y <= 1 / this.aspectRatio; + $.console.assert(validPoint, "[TileSource.getTileAtPoint] must be called with a valid point."); + + var widthScaled = this.dimensions.x * this.getLevelScale(level); + var pixelX = point.x * widthScaled; + var pixelY = point.y * widthScaled; + + var x = Math.floor(pixelX / this.getTileWidth(level)); + var y = Math.floor(pixelY / this.getTileHeight(level)); + + // When point.x == 1 or point.y == 1 / this.aspectRatio we want to + // return the last tile of the row/column + if (point.x >= 1) { + x = this.getNumTiles(level).x - 1; + } + var EPSILON = 1e-16; + if (point.y >= 1 / this.aspectRatio - EPSILON) { + y = this.getNumTiles(level).y - 1; + } + + return new $.Point(x, y); + }, + + /** + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + */ + getTileBounds: function( level, x, y ) { + var dimensionsScaled = this.dimensions.times( this.getLevelScale( level ) ), + tileWidth = this.getTileWidth(level), + tileHeight = this.getTileHeight(level), + px = ( x === 0 ) ? 0 : tileWidth * x - this.tileOverlap, + py = ( y === 0 ) ? 0 : tileHeight * y - this.tileOverlap, + sx = tileWidth + ( x === 0 ? 1 : 2 ) * this.tileOverlap, + sy = tileHeight + ( y === 0 ? 1 : 2 ) * this.tileOverlap, + scale = 1.0 / dimensionsScaled.x; + + sx = Math.min( sx, dimensionsScaled.x - px ); + sy = Math.min( sy, dimensionsScaled.y - py ); + + return new $.Rect( px * scale, py * scale, sx * scale, sy * scale ); + }, + + + /** + * Responsible for retrieving, and caching the + * image metadata pertinent to this TileSources implementation. + * @function + * @param {String} url + * @throws {Error} + */ + getImageInfo: function( url ) { + var _this = this, + callbackName, + callback, + readySource, + options, + urlParts, + filename, + lastDot; + + + if( url ) { + urlParts = url.split( '/' ); + filename = urlParts[ urlParts.length - 1 ]; + lastDot = filename.lastIndexOf( '.' ); + if ( lastDot > -1 ) { + urlParts[ urlParts.length - 1 ] = filename.slice( 0, lastDot ); + } + } + + callback = function( data ){ + if( typeof(data) === "string" ) { + data = $.parseXml( data ); + } + var $TileSource = $.TileSource.determineType( _this, data, url ); + if ( !$TileSource ) { + /** + * Raised when an error occurs loading a TileSource. + * + * @event open-failed + * @memberof OpenSeadragon.TileSource + * @type {object} + * @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event. + * @property {String} message + * @property {String} source + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( 'open-failed', { message: "Unable to load TileSource", source: url } ); + return; + } + + options = $TileSource.prototype.configure.apply( _this, [ data, url ]); + if (options.ajaxWithCredentials === undefined) { + options.ajaxWithCredentials = _this.ajaxWithCredentials; + } + + readySource = new $TileSource( options ); + _this.ready = true; + /** + * Raised when a TileSource is opened and initialized. + * + * @event ready + * @memberof OpenSeadragon.TileSource + * @type {object} + * @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event. + * @property {Object} tileSource + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( 'ready', { tileSource: readySource } ); + }; + + if( url.match(/\.js$/) ){ + //TODO: Its not very flexible to require tile sources to end jsonp + // request for info with a url that ends with '.js' but for + // now it's the only way I see to distinguish uniformly. + callbackName = url.split('/').pop().replace('.js', ''); + $.jsonp({ + url: url, + async: false, + callbackName: callbackName, + callback: callback + }); + } else { + // request info via xhr asynchronously. + $.makeAjaxRequest( { + url: url, + withCredentials: this.ajaxWithCredentials, + headers: this.ajaxHeaders, + success: function( xhr ) { + var data = processResponse( xhr ); + callback( data ); + }, + error: function ( xhr, exc ) { + var msg; + + /* + IE < 10 will block XHR requests to different origins. Any property access on the request + object will raise an exception which we'll attempt to handle by formatting the original + exception rather than the second one raised when we try to access xhr.status + */ + try { + msg = "HTTP " + xhr.status + " attempting to load TileSource"; + } catch ( e ) { + var formattedExc; + if ( typeof( exc ) == "undefined" || !exc.toString ) { + formattedExc = "Unknown error"; + } else { + formattedExc = exc.toString(); + } + + msg = formattedExc + " attempting to load TileSource"; + } + + /*** + * Raised when an error occurs loading a TileSource. + * + * @event open-failed + * @memberof OpenSeadragon.TileSource + * @type {object} + * @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event. + * @property {String} message + * @property {String} source + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( 'open-failed', { + message: msg, + source: url + }); + } + }); + } + + }, + + /** + * Responsible determining if a the particular TileSource supports the + * data format ( and allowed to apply logic against the url the data was + * loaded from, if any ). Overriding implementations are expected to do + * something smart with data and / or url to determine support. Also + * understand that iteration order of TileSources is not guarunteed so + * please make sure your data or url is expressive enough to ensure a simple + * and sufficient mechanisim for clear determination. + * @function + * @param {String|Object|Array|Document} data + * @param {String} url - the url the data was loaded + * from if any. + * @return {Boolean} + */ + supports: function( data, url ) { + return false; + }, + + /** + * Responsible for parsing and configuring the + * image metadata pertinent to this TileSources implementation. + * This method is not implemented by this class other than to throw an Error + * announcing you have to implement it. Because of the variety of tile + * server technologies, and various specifications for building image + * pyramids, this method is here to allow easy integration. + * @function + * @param {String|Object|Array|Document} data + * @param {String} url - the url the data was loaded + * from if any. + * @return {Object} options - A dictionary of keyword arguments sufficient + * to configure this tile sources constructor. + * @throws {Error} + */ + configure: function( data, url ) { + throw new Error( "Method not implemented." ); + }, + + /** + * Responsible for retrieving the url which will return an image for the + * region specified by the given x, y, and level components. + * This method is not implemented by this class other than to throw an Error + * announcing you have to implement it. Because of the variety of tile + * server technologies, and various specifications for building image + * pyramids, this method is here to allow easy integration. + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + * @throws {Error} + */ + getTileUrl: function( level, x, y ) { + throw new Error( "Method not implemented." ); + }, + + /** + * Responsible for retrieving the headers which will be attached to the image request for the + * region specified by the given x, y, and level components. + * This option is only relevant if {@link OpenSeadragon.Options}.loadTilesWithAjax is set to true. + * The headers returned here will override headers specified at the Viewer or TiledImage level. + * Specifying a falsy value for a header will clear its existing value set at the Viewer or + * TiledImage level (if any). + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + * @returns {Object} + */ + getTileAjaxHeaders: function( level, x, y ) { + return {}; + }, + + /** + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + */ + tileExists: function( level, x, y ) { + var numTiles = this.getNumTiles( level ); + return level >= this.minLevel && + level <= this.maxLevel && + x >= 0 && + y >= 0 && + x < numTiles.x && + y < numTiles.y; + } +}; + + +$.extend( true, $.TileSource.prototype, $.EventSource.prototype ); + + +/** + * Decides whether to try to process the response as xml, json, or hand back + * the text + * @private + * @inner + * @function + * @param {XMLHttpRequest} xhr - the completed network request + */ +function processResponse( xhr ){ + var responseText = xhr.responseText, + status = xhr.status, + statusText, + data; + + if ( !xhr ) { + throw new Error( $.getString( "Errors.Security" ) ); + } else if ( xhr.status !== 200 && xhr.status !== 0 ) { + status = xhr.status; + statusText = ( status == 404 ) ? + "Not Found" : + xhr.statusText; + throw new Error( $.getString( "Errors.Status", status, statusText ) ); + } + + if( responseText.match(/\s*<.*/) ){ + try{ + data = ( xhr.responseXML && xhr.responseXML.documentElement ) ? + xhr.responseXML : + $.parseXml( responseText ); + } catch (e){ + data = xhr.responseText; + } + }else if( responseText.match(/\s*[\{\[].*/) ){ + try{ + data = $.parseJSON(responseText); + } catch(e){ + data = responseText; + } + }else{ + data = responseText; + } + return data; +} + + +/** + * Determines the TileSource Implementation by introspection of OpenSeadragon + * namespace, calling each TileSource implementation of 'isType' + * @private + * @inner + * @function + * @param {Object|Array|Document} data - the tile source configuration object + * @param {String} url - the url where the tile source configuration object was + * loaded from, if any. + */ +$.TileSource.determineType = function( tileSource, data, url ){ + var property; + for( property in OpenSeadragon ){ + if( property.match(/.+TileSource$/) && + $.isFunction( OpenSeadragon[ property ] ) && + $.isFunction( OpenSeadragon[ property ].prototype.supports ) && + OpenSeadragon[ property ].prototype.supports.call( tileSource, data, url ) + ){ + return OpenSeadragon[ property ]; + } + } + + $.console.error( "No TileSource was able to open %s %s", url, data ); +}; + + +}( OpenSeadragon )); + +/* + * OpenSeadragon - DziTileSource + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class DziTileSource + * @memberof OpenSeadragon + * @extends OpenSeadragon.TileSource + * @param {Number|Object} width - the pixel width of the image or the idiomatic + * options object which is used instead of positional arguments. + * @param {Number} height + * @param {Number} tileSize + * @param {Number} tileOverlap + * @param {String} tilesUrl + * @param {String} fileFormat + * @param {OpenSeadragon.DisplayRect[]} displayRects + * @property {String} tilesUrl + * @property {String} fileFormat + * @property {OpenSeadragon.DisplayRect[]} displayRects + */ +$.DziTileSource = function( width, height, tileSize, tileOverlap, tilesUrl, fileFormat, displayRects, minLevel, maxLevel ) { + var i, + rect, + level, + options; + + if( $.isPlainObject( width ) ){ + options = width; + }else{ + options = { + width: arguments[ 0 ], + height: arguments[ 1 ], + tileSize: arguments[ 2 ], + tileOverlap: arguments[ 3 ], + tilesUrl: arguments[ 4 ], + fileFormat: arguments[ 5 ], + displayRects: arguments[ 6 ], + minLevel: arguments[ 7 ], + maxLevel: arguments[ 8 ] + }; + } + + this._levelRects = {}; + this.tilesUrl = options.tilesUrl; + this.fileFormat = options.fileFormat; + this.displayRects = options.displayRects; + + if ( this.displayRects ) { + for ( i = this.displayRects.length - 1; i >= 0; i-- ) { + rect = this.displayRects[ i ]; + for ( level = rect.minLevel; level <= rect.maxLevel; level++ ) { + if ( !this._levelRects[ level ] ) { + this._levelRects[ level ] = []; + } + this._levelRects[ level ].push( rect ); + } + } + } + + $.TileSource.apply( this, [ options ] ); + +}; + +$.extend( $.DziTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.DziTileSource.prototype */{ + + + /** + * Determine if the data and/or url imply the image service is supported by + * this tile source. + * @function + * @param {Object|Array} data + * @param {String} optional - url + */ + supports: function( data, url ){ + var ns; + if ( data.Image ) { + ns = data.Image.xmlns; + } else if ( data.documentElement) { + if ("Image" == data.documentElement.localName || "Image" == data.documentElement.tagName) { + ns = data.documentElement.namespaceURI; + } + } + + ns = (ns || '').toLowerCase(); + + return (ns.indexOf('schemas.microsoft.com/deepzoom/2008') !== -1 || + ns.indexOf('schemas.microsoft.com/deepzoom/2009') !== -1); + }, + + /** + * + * @function + * @param {Object|XMLDocument} data - the raw configuration + * @param {String} url - the url the data was retreived from if any. + * @return {Object} options - A dictionary of keyword arguments sufficient + * to configure this tile sources constructor. + */ + configure: function( data, url ){ + + var options; + + if( !$.isPlainObject(data) ){ + + options = configureFromXML( this, data ); + + }else{ + + options = configureFromObject( this, data ); + } + + if (url && !options.tilesUrl) { + options.tilesUrl = url.replace( + /([^\/]+?)(\.(dzi|xml|js)?(\?[^\/]*)?)?\/?$/, '$1_files/'); + + if (url.search(/\.(dzi|xml|js)\?/) != -1) { + options.queryParams = url.match(/\?.*/); + }else{ + options.queryParams = ''; + } + } + + return options; + }, + + + /** + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + */ + getTileUrl: function( level, x, y ) { + return [ this.tilesUrl, level, '/', x, '_', y, '.', this.fileFormat, this.queryParams ].join( '' ); + }, + + + /** + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + */ + tileExists: function( level, x, y ) { + var rects = this._levelRects[ level ], + rect, + scale, + xMin, + yMin, + xMax, + yMax, + i; + + if ( !rects || !rects.length ) { + return true; + } + + for ( i = rects.length - 1; i >= 0; i-- ) { + rect = rects[ i ]; + + if ( level < rect.minLevel || level > rect.maxLevel ) { + continue; + } + + scale = this.getLevelScale( level ); + xMin = rect.x * scale; + yMin = rect.y * scale; + xMax = xMin + rect.width * scale; + yMax = yMin + rect.height * scale; + + xMin = Math.floor( xMin / this._tileWidth ); + yMin = Math.floor( yMin / this._tileWidth ); // DZI tiles are square, so we just use _tileWidth + xMax = Math.ceil( xMax / this._tileWidth ); + yMax = Math.ceil( yMax / this._tileWidth ); + + if ( xMin <= x && x < xMax && yMin <= y && y < yMax ) { + return true; + } + } + + return false; + } +}); + + +/** + * @private + * @inner + * @function + */ +function configureFromXML( tileSource, xmlDoc ){ + + if ( !xmlDoc || !xmlDoc.documentElement ) { + throw new Error( $.getString( "Errors.Xml" ) ); + } + + var root = xmlDoc.documentElement, + rootName = root.localName || root.tagName, + ns = xmlDoc.documentElement.namespaceURI, + configuration = null, + displayRects = [], + dispRectNodes, + dispRectNode, + rectNode, + sizeNode, + i; + + if ( rootName == "Image" ) { + + try { + sizeNode = root.getElementsByTagName("Size" )[ 0 ]; + if (sizeNode === undefined) { + sizeNode = root.getElementsByTagNameNS(ns, "Size" )[ 0 ]; + } + + configuration = { + Image: { + xmlns: "http://schemas.microsoft.com/deepzoom/2008", + Url: root.getAttribute( "Url" ), + Format: root.getAttribute( "Format" ), + DisplayRect: null, + Overlap: parseInt( root.getAttribute( "Overlap" ), 10 ), + TileSize: parseInt( root.getAttribute( "TileSize" ), 10 ), + Size: { + Height: parseInt( sizeNode.getAttribute( "Height" ), 10 ), + Width: parseInt( sizeNode.getAttribute( "Width" ), 10 ) + } + } + }; + + if ( !$.imageFormatSupported( configuration.Image.Format ) ) { + throw new Error( + $.getString( "Errors.ImageFormat", configuration.Image.Format.toUpperCase() ) + ); + } + + dispRectNodes = root.getElementsByTagName("DisplayRect" ); + if (dispRectNodes === undefined) { + dispRectNodes = root.getElementsByTagNameNS(ns, "DisplayRect" )[ 0 ]; + } + + for ( i = 0; i < dispRectNodes.length; i++ ) { + dispRectNode = dispRectNodes[ i ]; + rectNode = dispRectNode.getElementsByTagName("Rect" )[ 0 ]; + if (rectNode === undefined) { + rectNode = dispRectNode.getElementsByTagNameNS(ns, "Rect" )[ 0 ]; + } + + displayRects.push({ + Rect: { + X: parseInt( rectNode.getAttribute( "X" ), 10 ), + Y: parseInt( rectNode.getAttribute( "Y" ), 10 ), + Width: parseInt( rectNode.getAttribute( "Width" ), 10 ), + Height: parseInt( rectNode.getAttribute( "Height" ), 10 ), + MinLevel: parseInt( dispRectNode.getAttribute( "MinLevel" ), 10 ), + MaxLevel: parseInt( dispRectNode.getAttribute( "MaxLevel" ), 10 ) + } + }); + } + + if( displayRects.length ){ + configuration.Image.DisplayRect = displayRects; + } + + return configureFromObject( tileSource, configuration ); + + } catch ( e ) { + throw (e instanceof Error) ? + e : + new Error( $.getString("Errors.Dzi") ); + } + } else if ( rootName == "Collection" ) { + throw new Error( $.getString( "Errors.Dzc" ) ); + } else if ( rootName == "Error" ) { + var messageNode = root.getElementsByTagName("Message")[0]; + var message = messageNode.firstChild.nodeValue; + throw new Error(message); + } + + throw new Error( $.getString( "Errors.Dzi" ) ); +} + +/** + * @private + * @inner + * @function + */ +function configureFromObject( tileSource, configuration ){ + var imageData = configuration.Image, + tilesUrl = imageData.Url, + fileFormat = imageData.Format, + sizeData = imageData.Size, + dispRectData = imageData.DisplayRect || [], + width = parseInt( sizeData.Width, 10 ), + height = parseInt( sizeData.Height, 10 ), + tileSize = parseInt( imageData.TileSize, 10 ), + tileOverlap = parseInt( imageData.Overlap, 10 ), + displayRects = [], + rectData, + i; + + //TODO: need to figure out out to better handle image format compatibility + // which actually includes additional file formats like xml and pdf + // and plain text for various tilesource implementations to avoid low + // level errors. + // + // For now, just don't perform the check. + // + /*if ( !imageFormatSupported( fileFormat ) ) { + throw new Error( + $.getString( "Errors.ImageFormat", fileFormat.toUpperCase() ) + ); + }*/ + + for ( i = 0; i < dispRectData.length; i++ ) { + rectData = dispRectData[ i ].Rect; + + displayRects.push( new $.DisplayRect( + parseInt( rectData.X, 10 ), + parseInt( rectData.Y, 10 ), + parseInt( rectData.Width, 10 ), + parseInt( rectData.Height, 10 ), + parseInt( rectData.MinLevel, 10 ), + parseInt( rectData.MaxLevel, 10 ) + )); + } + + return $.extend(true, { + width: width, /* width *required */ + height: height, /* height *required */ + tileSize: tileSize, /* tileSize *required */ + tileOverlap: tileOverlap, /* tileOverlap *required */ + minLevel: null, /* minLevel */ + maxLevel: null, /* maxLevel */ + tilesUrl: tilesUrl, /* tilesUrl */ + fileFormat: fileFormat, /* fileFormat */ + displayRects: displayRects /* displayRects */ + }, configuration ); + +} + +}( OpenSeadragon )); + +/* + * OpenSeadragon - IIIFTileSource + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class IIIFTileSource + * @classdesc A client implementation of the International Image Interoperability Framework + * Format: Image API 1.0 - 2.1 + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.TileSource + * @see http://iiif.io/api/image/ + */ +$.IIIFTileSource = function( options ){ + + /* eslint-disable camelcase */ + + $.extend( true, this, options ); + + if ( !( this.height && this.width && this['@id'] ) ) { + throw new Error( 'IIIF required parameters not provided.' ); + } + + options.tileSizePerScaleFactor = {}; + + // N.B. 2.0 renamed scale_factors to scaleFactors + if ( this.tile_width && this.tile_height ) { + options.tileWidth = this.tile_width; + options.tileHeight = this.tile_height; + } else if ( this.tile_width ) { + options.tileSize = this.tile_width; + } else if ( this.tile_height ) { + options.tileSize = this.tile_height; + } else if ( this.tiles ) { + // Version 2.0 forwards + if ( this.tiles.length == 1 ) { + options.tileWidth = this.tiles[0].width; + // Use height if provided, otherwise assume square tiles and use width. + options.tileHeight = this.tiles[0].height || this.tiles[0].width; + this.scale_factors = this.tiles[0].scaleFactors; + } else { + // Multiple tile sizes at different levels + this.scale_factors = []; + for (var t = 0; t < this.tiles.length; t++ ) { + for (var sf = 0; sf < this.tiles[t].scaleFactors.length; sf++) { + var scaleFactor = this.tiles[t].scaleFactors[sf]; + this.scale_factors.push(scaleFactor); + options.tileSizePerScaleFactor[scaleFactor] = { + width: this.tiles[t].width, + height: this.tiles[t].height || this.tiles[t].width + }; + } + } + } + } else if ( canBeTiled(options.profile) ) { + // use the largest of tileOptions that is smaller than the short dimension + var shortDim = Math.min( this.height, this.width ), + tileOptions = [256, 512, 1024], + smallerTiles = []; + + for ( var c = 0; c < tileOptions.length; c++ ) { + if ( tileOptions[c] <= shortDim ) { + smallerTiles.push( tileOptions[c] ); + } + } + + if ( smallerTiles.length > 0 ) { + options.tileSize = Math.max.apply( null, smallerTiles ); + } else { + // If we're smaller than 256, just use the short side. + options.tileSize = shortDim; + } + } else if (this.sizes && this.sizes.length > 0) { + // This info.json can't be tiled, but we can still construct a legacy pyramid from the sizes array. + // In this mode, IIIFTileSource will call functions from the abstract baseTileSource or the + // LegacyTileSource instead of performing IIIF tiling. + this.emulateLegacyImagePyramid = true; + + options.levels = constructLevels( this ); + // use the largest available size to define tiles + $.extend( true, options, { + width: options.levels[ options.levels.length - 1 ].width, + height: options.levels[ options.levels.length - 1 ].height, + tileSize: Math.max( options.height, options.width ), + tileOverlap: 0, + minLevel: 0, + maxLevel: options.levels.length - 1 + }); + this.levels = options.levels; + } else { + $.console.error("Nothing in the info.json to construct image pyramids from"); + } + + if (!options.maxLevel && !this.emulateLegacyImagePyramid) { + if (!this.scale_factors) { + options.maxLevel = Number(Math.ceil(Math.log(Math.max(this.width, this.height), 2))); + } else { + options.maxLevel = Math.floor(Math.pow(Math.max.apply(null, this.scale_factors), 0.5)); + } + } + + $.TileSource.apply( this, [ options ] ); +}; + +$.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.IIIFTileSource.prototype */{ + /** + * Determine if the data and/or url imply the image service is supported by + * this tile source. + * @function + * @param {Object|Array} data + * @param {String} optional - url + */ + + supports: function( data, url ) { + // Version 2.0 and forwards + if (data.protocol && data.protocol == 'http://iiif.io/api/image') { + return true; + // Version 1.1 + } else if ( data['@context'] && ( + data['@context'] == "http://library.stanford.edu/iiif/image-api/1.1/context.json" || + data['@context'] == "http://iiif.io/api/image/1/context.json") ) { + // N.B. the iiif.io context is wrong, but where the representation lives so likely to be used + return true; + + // Version 1.0 + } else if ( data.profile && + data.profile.indexOf("http://library.stanford.edu/iiif/image-api/compliance.html") === 0) { + return true; + } else if ( data.identifier && data.width && data.height ) { + return true; + } else if ( data.documentElement && + "info" == data.documentElement.tagName && + "http://library.stanford.edu/iiif/image-api/ns/" == + data.documentElement.namespaceURI) { + return true; + + // Not IIIF + } else { + return false; + } + }, + + /** + * + * @function + * @param {Object} data - the raw configuration + * @example IIIF 1.1 Info Looks like this + * { + * "@context" : "http://library.stanford.edu/iiif/image-api/1.1/context.json", + * "@id" : "http://iiif.example.com/prefix/1E34750D-38DB-4825-A38A-B60A345E591C", + * "width" : 6000, + * "height" : 4000, + * "scale_factors" : [ 1, 2, 4 ], + * "tile_width" : 1024, + * "tile_height" : 1024, + * "formats" : [ "jpg", "png" ], + * "qualities" : [ "native", "grey" ], + * "profile" : "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0" + * } + */ + configure: function( data, url ){ + // Try to deduce our version and fake it upwards if needed + if ( !$.isPlainObject(data) ) { + var options = configureFromXml10( data ); + options['@context'] = "http://iiif.io/api/image/1.0/context.json"; + options['@id'] = url.replace('/info.xml', ''); + return options; + } else if ( !data['@context'] ) { + data['@context'] = 'http://iiif.io/api/image/1.0/context.json'; + data['@id'] = url.replace('/info.json', ''); + return data; + } else { + return data; + } + }, + + /** + * Return the tileWidth for the given level. + * @function + * @param {Number} level + */ + getTileWidth: function( level ) { + + if(this.emulateLegacyImagePyramid) { + return $.TileSource.prototype.getTileWidth.call(this, level); + } + + var scaleFactor = Math.pow(2, this.maxLevel - level); + + if (this.tileSizePerScaleFactor && this.tileSizePerScaleFactor[scaleFactor]) { + return this.tileSizePerScaleFactor[scaleFactor].width; + } + return this._tileWidth; + }, + + /** + * Return the tileHeight for the given level. + * @function + * @param {Number} level + */ + getTileHeight: function( level ) { + + if(this.emulateLegacyImagePyramid) { + return $.TileSource.prototype.getTileHeight.call(this, level); + } + + var scaleFactor = Math.pow(2, this.maxLevel - level); + + if (this.tileSizePerScaleFactor && this.tileSizePerScaleFactor[scaleFactor]) { + return this.tileSizePerScaleFactor[scaleFactor].height; + } + return this._tileHeight; + }, + + /** + * @function + * @param {Number} level + */ + getLevelScale: function ( level ) { + + if(this.emulateLegacyImagePyramid) { + var levelScale = NaN; + if (this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel) { + levelScale = + this.levels[level].width / + this.levels[this.maxLevel].width; + } + return levelScale; + } + + return $.TileSource.prototype.getLevelScale.call(this, level); + }, + + /** + * @function + * @param {Number} level + */ + getNumTiles: function( level ) { + + if(this.emulateLegacyImagePyramid) { + var scale = this.getLevelScale(level); + if (scale) { + return new $.Point(1, 1); + } else { + return new $.Point(0, 0); + } + } + + return $.TileSource.prototype.getNumTiles.call(this, level); + }, + + + /** + * @function + * @param {Number} level + * @param {OpenSeadragon.Point} point + */ + getTileAtPoint: function( level, point ) { + + if(this.emulateLegacyImagePyramid) { + return new $.Point(0, 0); + } + + return $.TileSource.prototype.getTileAtPoint.call(this, level, point); + }, + + + /** + * Responsible for retrieving the url which will return an image for the + * region specified by the given x, y, and level components. + * @function + * @param {Number} level - z index + * @param {Number} x + * @param {Number} y + * @throws {Error} + */ + getTileUrl: function( level, x, y ){ + + if(this.emulateLegacyImagePyramid) { + var url = null; + if ( this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel ) { + url = this.levels[ level ].url; + } + return url; + } + + //# constants + var IIIF_ROTATION = '0', + //## get the scale (level as a decimal) + scale = Math.pow( 0.5, this.maxLevel - level ), + + //# image dimensions at this level + levelWidth = Math.ceil( this.width * scale ), + levelHeight = Math.ceil( this.height * scale ), + + //## iiif region + tileWidth, + tileHeight, + iiifTileSizeWidth, + iiifTileSizeHeight, + iiifRegion, + iiifTileX, + iiifTileY, + iiifTileW, + iiifTileH, + iiifSize, + iiifQuality, + uri; + + tileWidth = this.getTileWidth(level); + tileHeight = this.getTileHeight(level); + iiifTileSizeWidth = Math.ceil( tileWidth / scale ); + iiifTileSizeHeight = Math.ceil( tileHeight / scale ); + + if ( this['@context'].indexOf('/1.0/context.json') > -1 || + this['@context'].indexOf('/1.1/context.json') > -1 || + this['@context'].indexOf('/1/context.json') > -1 ) { + iiifQuality = "native.jpg"; + } else { + iiifQuality = "default.jpg"; + } + + if ( levelWidth < tileWidth && levelHeight < tileHeight ){ + iiifSize = levelWidth + ","; + iiifRegion = 'full'; + } else { + iiifTileX = x * iiifTileSizeWidth; + iiifTileY = y * iiifTileSizeHeight; + iiifTileW = Math.min( iiifTileSizeWidth, this.width - iiifTileX ); + iiifTileH = Math.min( iiifTileSizeHeight, this.height - iiifTileY ); + iiifSize = Math.ceil( iiifTileW * scale ) + ","; + iiifRegion = [ iiifTileX, iiifTileY, iiifTileW, iiifTileH ].join( ',' ); + } + uri = [ this['@id'], iiifRegion, iiifSize, IIIF_ROTATION, iiifQuality ].join( '/' ); + + return uri; + } + + }); + + /** + * Determine whether arbitrary tile requests can be made against a service with the given profile + * @function + * @param {object} profile - IIIF profile object + * @throws {Error} + */ + function canBeTiled (profile ) { + var level0Profiles = [ + "http://library.stanford.edu/iiif/image-api/compliance.html#level0", + "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0", + "http://iiif.io/api/image/2/level0.json" + ]; + var isLevel0 = (level0Profiles.indexOf(profile[0]) != -1); + return !isLevel0 || (profile.indexOf("sizeByW") != -1); + } + + /** + * Build the legacy pyramid URLs (one tile per level) + * @function + * @param {object} options - infoJson + * @throws {Error} + */ + function constructLevels(options) { + var levels = []; + for(var i = 0; i < options.sizes.length; i++) { + levels.push({ + url: options['@id'] + '/full/' + options.sizes[i].width + ',/0/default.jpg', + width: options.sizes[i].width, + height: options.sizes[i].height + }); + } + return levels.sort(function(a, b) { + return a.width - b.width; + }); + } + + + function configureFromXml10(xmlDoc) { + //parse the xml + if ( !xmlDoc || !xmlDoc.documentElement ) { + throw new Error( $.getString( "Errors.Xml" ) ); + } + + var root = xmlDoc.documentElement, + rootName = root.tagName, + configuration = null; + + if ( rootName == "info" ) { + try { + configuration = {}; + parseXML10( root, configuration ); + return configuration; + + } catch ( e ) { + throw (e instanceof Error) ? + e : + new Error( $.getString("Errors.IIIF") ); + } + } + throw new Error( $.getString( "Errors.IIIF" ) ); + } + + function parseXML10( node, configuration, property ) { + var i, + value; + if ( node.nodeType == 3 && property ) {//text node + value = node.nodeValue.trim(); + if( value.match(/^\d*$/)){ + value = Number( value ); + } + if( !configuration[ property ] ){ + configuration[ property ] = value; + }else{ + if( !$.isArray( configuration[ property ] ) ){ + configuration[ property ] = [ configuration[ property ] ]; + } + configuration[ property ].push( value ); + } + } else if( node.nodeType == 1 ){ + for( i = 0; i < node.childNodes.length; i++ ){ + parseXML10( node.childNodes[ i ], configuration, node.nodeName ); + } + } + } + + + +}( OpenSeadragon )); + +/* + * OpenSeadragon - OsmTileSource + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Derived from the OSM tile source in Rainer Simon's seajax-utils project + * . Rainer Simon has contributed + * the included code to the OpenSeadragon project under the New BSD license; + * see . + */ + + +(function( $ ){ + +/** + * @class OsmTileSource + * @classdesc A tilesource implementation for OpenStreetMap.

      + * + * Note 1. Zoomlevels. Deep Zoom and OSM define zoom levels differently. In Deep + * Zoom, level 0 equals an image of 1x1 pixels. In OSM, level 0 equals an image of + * 256x256 levels (see http://gasi.ch/blog/inside-deep-zoom-2). I.e. there is a + * difference of log2(256)=8 levels.

      + * + * Note 2. Image dimension. According to the OSM Wiki + * (http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Zoom_levels) + * the highest Mapnik zoom level has 256.144x256.144 tiles, with a 256x256 + * pixel size. I.e. the Deep Zoom image dimension is 65.572.864x65.572.864 + * pixels. + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.TileSource + * @param {Number|Object} width - the pixel width of the image or the idiomatic + * options object which is used instead of positional arguments. + * @param {Number} height + * @param {Number} tileSize + * @param {Number} tileOverlap + * @param {String} tilesUrl + */ +$.OsmTileSource = function( width, height, tileSize, tileOverlap, tilesUrl ) { + var options; + + if( $.isPlainObject( width ) ){ + options = width; + }else{ + options = { + width: arguments[0], + height: arguments[1], + tileSize: arguments[2], + tileOverlap: arguments[3], + tilesUrl: arguments[4] + }; + } + //apply default setting for standard public OpenStreatMaps service + //but allow them to be specified so fliks can host there own instance + //or apply against other services supportting the same standard + if( !options.width || !options.height ){ + options.width = 65572864; + options.height = 65572864; + } + if( !options.tileSize ){ + options.tileSize = 256; + options.tileOverlap = 0; + } + if( !options.tilesUrl ){ + options.tilesUrl = "http://tile.openstreetmap.org/"; + } + options.minLevel = 8; + + $.TileSource.apply( this, [ options ] ); + +}; + +$.extend( $.OsmTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.OsmTileSource.prototype */{ + + + /** + * Determine if the data and/or url imply the image service is supported by + * this tile source. + * @function + * @param {Object|Array} data + * @param {String} optional - url + */ + supports: function( data, url ){ + return ( + data.type && + "openstreetmaps" == data.type + ); + }, + + /** + * + * @function + * @param {Object} data - the raw configuration + * @param {String} url - the url the data was retreived from if any. + * @return {Object} options - A dictionary of keyword arguments sufficient + * to configure this tile sources constructor. + */ + configure: function( data, url ){ + return data; + }, + + + /** + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + */ + getTileUrl: function( level, x, y ) { + return this.tilesUrl + (level - 8) + "/" + x + "/" + y + ".png"; + } +}); + + +}( OpenSeadragon )); + +/* + * OpenSeadragon - TmsTileSource + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Derived from the TMS tile source in Rainer Simon's seajax-utils project + * . Rainer Simon has contributed + * the included code to the OpenSeadragon project under the New BSD license; + * see . + */ + + +(function( $ ){ + +/** + * @class TmsTileSource + * @classdesc A tilesource implementation for Tiled Map Services (TMS). + * TMS tile scheme ( [ as supported by OpenLayers ] is described here + * ( http://openlayers.org/dev/examples/tms.html ). + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.TileSource + * @param {Number|Object} width - the pixel width of the image or the idiomatic + * options object which is used instead of positional arguments. + * @param {Number} height + * @param {Number} tileSize + * @param {Number} tileOverlap + * @param {String} tilesUrl + */ +$.TmsTileSource = function( width, height, tileSize, tileOverlap, tilesUrl ) { + var options; + + if( $.isPlainObject( width ) ){ + options = width; + }else{ + options = { + width: arguments[0], + height: arguments[1], + tileSize: arguments[2], + tileOverlap: arguments[3], + tilesUrl: arguments[4] + }; + } + // TMS has integer multiples of 256 for width/height and adds buffer + // if necessary -> account for this! + var bufferedWidth = Math.ceil(options.width / 256) * 256, + bufferedHeight = Math.ceil(options.height / 256) * 256, + max; + + // Compute number of zoomlevels in this tileset + if (bufferedWidth > bufferedHeight) { + max = bufferedWidth / 256; + } else { + max = bufferedHeight / 256; + } + options.maxLevel = Math.ceil(Math.log(max) / Math.log(2)) - 1; + options.tileSize = 256; + options.width = bufferedWidth; + options.height = bufferedHeight; + + $.TileSource.apply( this, [ options ] ); + +}; + +$.extend( $.TmsTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.TmsTileSource.prototype */{ + + + /** + * Determine if the data and/or url imply the image service is supported by + * this tile source. + * @function + * @param {Object|Array} data + * @param {String} optional - url + */ + supports: function( data, url ){ + return ( data.type && "tiledmapservice" == data.type ); + }, + + /** + * + * @function + * @param {Object} data - the raw configuration + * @param {String} url - the url the data was retreived from if any. + * @return {Object} options - A dictionary of keyword arguments sufficient + * to configure this tile sources constructor. + */ + configure: function( data, url ){ + return data; + }, + + + /** + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + */ + getTileUrl: function( level, x, y ) { + // Convert from Deep Zoom definition to TMS zoom definition + var yTiles = this.getNumTiles( level ).y - 1; + + return this.tilesUrl + level + "/" + x + "/" + (yTiles - y) + ".png"; + } +}); + + +}( OpenSeadragon )); + +(function($) { + + /** + * @class ZoomifyTileSource + * @classdesc A tilesource implementation for the zoomify format. + * + * A description of the format can be found here: + * https://ecommons.cornell.edu/bitstream/handle/1813/5410/Introducing_Zoomify_Image.pdf + * + * There are two ways of creating a zoomify tilesource for openseadragon + * + * 1) Supplying all necessary information in the tilesource object. A minimal example object for this method looks like this: + * + * { + * type: "zoomifytileservice", + * width: 1000, + * height: 1000, + * tilesUrl: "/test/data/zoomify/" + * } + * + * The tileSize is currently hardcoded to 256 (the usual Zoomify default). The tileUrl must the path to the image _directory_. + * + * 2) Loading image metadata from xml file: (CURRENTLY NOT SUPPORTED) + * + * When creating zoomify formatted images one "xml" like file with name ImageProperties.xml + * will be created as well. Here is an example of such a file: + * + * + * + * To use this xml file as metadata source you must supply the path to the ImageProperties.xml file and leave out all other parameters: + * As stated above, this method of loading a zoomify tilesource is currently not supported + * + * { + * type: "zoomifytileservice", + * tilesUrl: "/test/data/zoomify/ImageProperties.xml" + * } + + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.TileSource + * @param {Number} width - the pixel width of the image. + * @param {Number} height + * @param {Number} tileSize + * @param {String} tilesUrl + */ + $.ZoomifyTileSource = function(options) { + options.tileSize = 256; + + var currentImageSize = { + x: options.width, + y: options.height + }; + options.imageSizes = [{ + x: options.width, + y: options.height + }]; + options.gridSize = [this._getGridSize(options.width, options.height, options.tileSize)]; + + while (parseInt(currentImageSize.x, 10) > options.tileSize || parseInt(currentImageSize.y, 10) > options.tileSize) { + currentImageSize.x = Math.floor(currentImageSize.x / 2); + currentImageSize.y = Math.floor(currentImageSize.y / 2); + options.imageSizes.push({ + x: currentImageSize.x, + y: currentImageSize.y + }); + options.gridSize.push(this._getGridSize(currentImageSize.x, currentImageSize.y, options.tileSize)); + } + options.imageSizes.reverse(); + options.gridSize.reverse(); + options.minLevel = 0; + options.maxLevel = options.gridSize.length - 1; + + OpenSeadragon.TileSource.apply(this, [options]); + }; + + $.extend($.ZoomifyTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.ZoomifyTileSource.prototype */ { + + //private + _getGridSize: function(width, height, tileSize) { + return { + x: Math.ceil(width / tileSize), + y: Math.ceil(height / tileSize) + }; + }, + + //private + _calculateAbsoluteTileNumber: function(level, x, y) { + var num = 0; + var size = {}; + + //Sum up all tiles below the level we want the number of tiles + for (var z = 0; z < level; z++) { + size = this.gridSize[z]; + num += size.x * size.y; + } + //Add the tiles of the level + size = this.gridSize[level]; + num += size.x * y + x; + return num; + }, + + /** + * Determine if the data and/or url imply the image service is supported by + * this tile source. + * @function + * @param {Object|Array} data + * @param {String} optional - url + */ + supports: function(data, url) { + return (data.type && "zoomifytileservice" == data.type); + }, + + /** + * + * @function + * @param {Object} data - the raw configuration + * @param {String} url - the url the data was retreived from if any. + * @return {Object} options - A dictionary of keyword arguments sufficient + * to configure this tile sources constructor. + */ + configure: function(data, url) { + return data; + }, + + /** + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + */ + getTileUrl: function(level, x, y) { + //console.log(level); + var result = 0; + var num = this._calculateAbsoluteTileNumber(level, x, y); + result = Math.floor(num / 256); + return this.tilesUrl + 'TileGroup' + result + '/' + level + '-' + x + '-' + y + '.jpg'; + + } + }); + +}(OpenSeadragon)); + + +/* + * OpenSeadragon - LegacyTileSource + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class LegacyTileSource + * @classdesc The LegacyTileSource allows simple, traditional image pyramids to be loaded + * into an OpenSeadragon Viewer. Basically, this translates to the historically + * common practice of starting with a 'master' image, maybe a tiff for example, + * and generating a set of 'service' images like one or more thumbnails, a medium + * resolution image and a high resolution image in standard web formats like + * png or jpg. + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.TileSource + * @param {Array} levels An array of file descriptions, each is an object with + * a 'url', a 'width', and a 'height'. Overriding classes can expect more + * properties but these properties are sufficient for this implementation. + * Additionally, the levels are required to be listed in order from + * smallest to largest. + * @property {Number} aspectRatio + * @property {Number} dimensions + * @property {Number} tileSize + * @property {Number} tileOverlap + * @property {Number} minLevel + * @property {Number} maxLevel + * @property {Array} levels + */ +$.LegacyTileSource = function( levels ) { + + var options, + width, + height; + + if( $.isArray( levels ) ){ + options = { + type: 'legacy-image-pyramid', + levels: levels + }; + } + + //clean up the levels to make sure we support all formats + options.levels = filterFiles( options.levels ); + + if ( options.levels.length > 0 ) { + width = options.levels[ options.levels.length - 1 ].width; + height = options.levels[ options.levels.length - 1 ].height; + } + else { + width = 0; + height = 0; + $.console.error( "No supported image formats found" ); + } + + $.extend( true, options, { + width: width, + height: height, + tileSize: Math.max( height, width ), + tileOverlap: 0, + minLevel: 0, + maxLevel: options.levels.length > 0 ? options.levels.length - 1 : 0 + } ); + + $.TileSource.apply( this, [ options ] ); + + this.levels = options.levels; +}; + +$.extend( $.LegacyTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.LegacyTileSource.prototype */{ + /** + * Determine if the data and/or url imply the image service is supported by + * this tile source. + * @function + * @param {Object|Array} data + * @param {String} optional - url + */ + supports: function( data, url ){ + return ( + data.type && + "legacy-image-pyramid" == data.type + ) || ( + data.documentElement && + "legacy-image-pyramid" == data.documentElement.getAttribute('type') + ); + }, + + + /** + * + * @function + * @param {Object|XMLDocument} configuration - the raw configuration + * @param {String} dataUrl - the url the data was retreived from if any. + * @return {Object} options - A dictionary of keyword arguments sufficient + * to configure this tile sources constructor. + */ + configure: function( configuration, dataUrl ){ + + var options; + + if( !$.isPlainObject(configuration) ){ + + options = configureFromXML( this, configuration ); + + }else{ + + options = configureFromObject( this, configuration ); + } + + return options; + + }, + + /** + * @function + * @param {Number} level + */ + getLevelScale: function ( level ) { + var levelScale = NaN; + if ( this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel ) { + levelScale = + this.levels[ level ].width / + this.levels[ this.maxLevel ].width; + } + return levelScale; + }, + + /** + * @function + * @param {Number} level + */ + getNumTiles: function( level ) { + var scale = this.getLevelScale( level ); + if ( scale ){ + return new $.Point( 1, 1 ); + } else { + return new $.Point( 0, 0 ); + } + }, + + /** + * This method is not implemented by this class other than to throw an Error + * announcing you have to implement it. Because of the variety of tile + * server technologies, and various specifications for building image + * pyramids, this method is here to allow easy integration. + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + * @throws {Error} + */ + getTileUrl: function ( level, x, y ) { + var url = null; + if ( this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel ) { + url = this.levels[ level ].url; + } + return url; + } +} ); + +/** + * This method removes any files from the Array which dont conform to our + * basic requirements for a 'level' in the LegacyTileSource. + * @private + * @inner + * @function + */ +function filterFiles( files ){ + var filtered = [], + file, + i; + for( i = 0; i < files.length; i++ ){ + file = files[ i ]; + if( file.height && + file.width && + file.url ){ + //This is sufficient to serve as a level + filtered.push({ + url: file.url, + width: Number( file.width ), + height: Number( file.height ) + }); + } + else { + $.console.error( 'Unsupported image format: %s', file.url ? file.url : '' ); + } + } + + return filtered.sort(function(a, b) { + return a.height - b.height; + }); + +} + +/** + * @private + * @inner + * @function + */ +function configureFromXML( tileSource, xmlDoc ){ + + if ( !xmlDoc || !xmlDoc.documentElement ) { + throw new Error( $.getString( "Errors.Xml" ) ); + } + + var root = xmlDoc.documentElement, + rootName = root.tagName, + conf = null, + levels = [], + level, + i; + + if ( rootName == "image" ) { + + try { + conf = { + type: root.getAttribute( "type" ), + levels: [] + }; + + levels = root.getElementsByTagName( "level" ); + for ( i = 0; i < levels.length; i++ ) { + level = levels[ i ]; + + conf.levels.push({ + url: level.getAttribute( "url" ), + width: parseInt( level.getAttribute( "width" ), 10 ), + height: parseInt( level.getAttribute( "height" ), 10 ) + }); + } + + return configureFromObject( tileSource, conf ); + + } catch ( e ) { + throw (e instanceof Error) ? + e : + new Error( 'Unknown error parsing Legacy Image Pyramid XML.' ); + } + } else if ( rootName == "collection" ) { + throw new Error( 'Legacy Image Pyramid Collections not yet supported.' ); + } else if ( rootName == "error" ) { + throw new Error( 'Error: ' + xmlDoc ); + } + + throw new Error( 'Unknown element ' + rootName ); +} + +/** + * @private + * @inner + * @function + */ +function configureFromObject( tileSource, configuration ){ + + return configuration.levels; + +} + +}( OpenSeadragon )); + +/* + * OpenSeadragon - ImageTileSource + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function ($) { + + /** + * @class ImageTileSource + * @classdesc The ImageTileSource allows a simple image to be loaded + * into an OpenSeadragon Viewer. + * There are 2 ways to open an ImageTileSource: + * 1. viewer.open({type: 'image', url: fooUrl}); + * 2. viewer.open(new OpenSeadragon.ImageTileSource({url: fooUrl})); + * + * With the first syntax, the crossOriginPolicy, ajaxWithCredentials and + * useCanvas options are inherited from the viewer if they are not + * specified directly in the options object. + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.TileSource + * @param {Object} options Options object. + * @param {String} options.url URL of the image + * @param {Boolean} [options.buildPyramid=true] If set to true (default), a + * pyramid will be built internally to provide a better downsampling. + * @param {String|Boolean} [options.crossOriginPolicy=false] Valid values are + * 'Anonymous', 'use-credentials', and false. If false, image requests will + * not use CORS preventing internal pyramid building for images from other + * domains. + * @param {String|Boolean} [options.ajaxWithCredentials=false] Whether to set + * the withCredentials XHR flag for AJAX requests (when loading tile sources). + * @param {Boolean} [options.useCanvas=true] Set to false to prevent any use + * of the canvas API. + */ + $.ImageTileSource = function (options) { + + options = $.extend({ + buildPyramid: true, + crossOriginPolicy: false, + ajaxWithCredentials: false, + useCanvas: true + }, options); + $.TileSource.apply(this, [options]); + + }; + + $.extend($.ImageTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.ImageTileSource.prototype */{ + /** + * Determine if the data and/or url imply the image service is supported by + * this tile source. + * @function + * @param {Object|Array} data + * @param {String} optional - url + */ + supports: function (data, url) { + return data.type && data.type === "image"; + }, + /** + * + * @function + * @param {Object} options - the options + * @param {String} dataUrl - the url the image was retreived from, if any. + * @return {Object} options - A dictionary of keyword arguments sufficient + * to configure this tile sources constructor. + */ + configure: function (options, dataUrl) { + return options; + }, + /** + * Responsible for retrieving, and caching the + * image metadata pertinent to this TileSources implementation. + * @function + * @param {String} url + * @throws {Error} + */ + getImageInfo: function (url) { + var image = this._image = new Image(); + var _this = this; + + if (this.crossOriginPolicy) { + image.crossOrigin = this.crossOriginPolicy; + } + if (this.ajaxWithCredentials) { + image.useCredentials = this.ajaxWithCredentials; + } + + $.addEvent(image, 'load', function () { + /* IE8 fix since it has no naturalWidth and naturalHeight */ + _this.width = Object.prototype.hasOwnProperty.call(image, 'naturalWidth') ? image.naturalWidth : image.width; + _this.height = Object.prototype.hasOwnProperty.call(image, 'naturalHeight') ? image.naturalHeight : image.height; + _this.aspectRatio = _this.width / _this.height; + _this.dimensions = new $.Point(_this.width, _this.height); + _this._tileWidth = _this.width; + _this._tileHeight = _this.height; + _this.tileOverlap = 0; + _this.minLevel = 0; + _this.levels = _this._buildLevels(); + _this.maxLevel = _this.levels.length - 1; + + _this.ready = true; + + // Note: this event is documented elsewhere, in TileSource + _this.raiseEvent('ready', {tileSource: _this}); + }); + + $.addEvent(image, 'error', function () { + // Note: this event is documented elsewhere, in TileSource + _this.raiseEvent('open-failed', { + message: "Error loading image at " + url, + source: url + }); + }); + + image.src = url; + }, + /** + * @function + * @param {Number} level + */ + getLevelScale: function (level) { + var levelScale = NaN; + if (level >= this.minLevel && level <= this.maxLevel) { + levelScale = + this.levels[level].width / + this.levels[this.maxLevel].width; + } + return levelScale; + }, + /** + * @function + * @param {Number} level + */ + getNumTiles: function (level) { + var scale = this.getLevelScale(level); + if (scale) { + return new $.Point(1, 1); + } else { + return new $.Point(0, 0); + } + }, + /** + * Retrieves a tile url + * @function + * @param {Number} level Level of the tile + * @param {Number} x x coordinate of the tile + * @param {Number} y y coordinate of the tile + */ + getTileUrl: function (level, x, y) { + var url = null; + if (level >= this.minLevel && level <= this.maxLevel) { + url = this.levels[level].url; + } + return url; + }, + /** + * Retrieves a tile context 2D + * @function + * @param {Number} level Level of the tile + * @param {Number} x x coordinate of the tile + * @param {Number} y y coordinate of the tile + */ + getContext2D: function (level, x, y) { + var context = null; + if (level >= this.minLevel && level <= this.maxLevel) { + context = this.levels[level].context2D; + } + return context; + }, + + // private + // + // Builds the differents levels of the pyramid if possible + // (i.e. if canvas API enabled and no canvas tainting issue). + _buildLevels: function () { + var levels = [{ + url: this._image.src, + /* IE8 fix since it has no naturalWidth and naturalHeight */ + width: Object.prototype.hasOwnProperty.call(this._image, 'naturalWidth') ? this._image.naturalWidth : this._image.width, + height: Object.prototype.hasOwnProperty.call(this._image, 'naturalHeight') ? this._image.naturalHeight : this._image.height + }]; + + if (!this.buildPyramid || !$.supportsCanvas || !this.useCanvas) { + // We don't need the image anymore. Allows it to be GC. + delete this._image; + return levels; + } + + /* IE8 fix since it has no naturalWidth and naturalHeight */ + var currentWidth = Object.prototype.hasOwnProperty.call(this._image, 'naturalWidth') ? this._image.naturalWidth : this._image.width; + var currentHeight = Object.prototype.hasOwnProperty.call(this._image, 'naturalHeight') ? this._image.naturalHeight : this._image.height; + + + var bigCanvas = document.createElement("canvas"); + var bigContext = bigCanvas.getContext("2d"); + + bigCanvas.width = currentWidth; + bigCanvas.height = currentHeight; + bigContext.drawImage(this._image, 0, 0, currentWidth, currentHeight); + // We cache the context of the highest level because the browser + // is a lot faster at downsampling something it already has + // downsampled before. + levels[0].context2D = bigContext; + // We don't need the image anymore. Allows it to be GC. + delete this._image; + + if ($.isCanvasTainted(bigCanvas)) { + // If the canvas is tainted, we can't compute the pyramid. + return levels; + } + + // We build smaller levels until either width or height becomes + // 1 pixel wide. + while (currentWidth >= 2 && currentHeight >= 2) { + currentWidth = Math.floor(currentWidth / 2); + currentHeight = Math.floor(currentHeight / 2); + var smallCanvas = document.createElement("canvas"); + var smallContext = smallCanvas.getContext("2d"); + smallCanvas.width = currentWidth; + smallCanvas.height = currentHeight; + smallContext.drawImage(bigCanvas, 0, 0, currentWidth, currentHeight); + + levels.splice(0, 0, { + context2D: smallContext, + width: currentWidth, + height: currentHeight + }); + + bigCanvas = smallCanvas; + bigContext = smallContext; + } + return levels; + } + }); + +}(OpenSeadragon)); + +/* + * OpenSeadragon - TileSourceCollection + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function($) { + +// deprecated +$.TileSourceCollection = function(tileSize, tileSources, rows, layout) { + $.console.error('TileSourceCollection is deprecated; use World instead'); +}; + +}(OpenSeadragon)); + +/* + * OpenSeadragon - Button + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * An enumeration of button states + * @member ButtonState + * @memberof OpenSeadragon + * @static + * @type {Object} + * @property {Number} REST + * @property {Number} GROUP + * @property {Number} HOVER + * @property {Number} DOWN + */ +$.ButtonState = { + REST: 0, + GROUP: 1, + HOVER: 2, + DOWN: 3 +}; + +/** + * @class Button + * @classdesc Manages events, hover states for individual buttons, tool-tips, as well + * as fading the buttons out when the user has not interacted with them + * for a specified period. + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.EventSource + * @param {Object} options + * @param {Element} [options.element=null] Element to use as the button. If not specified, an HTML <div> element is created. + * @param {String} [options.tooltip=null] Provides context help for the button when the + * user hovers over it. + * @param {String} [options.srcRest=null] URL of image to use in 'rest' state. + * @param {String} [options.srcGroup=null] URL of image to use in 'up' state. + * @param {String} [options.srcHover=null] URL of image to use in 'hover' state. + * @param {String} [options.srcDown=null] URL of image to use in 'down' state. + * @param {Number} [options.fadeDelay=0] How long to wait before fading. + * @param {Number} [options.fadeLength=2000] How long should it take to fade the button. + * @param {OpenSeadragon.EventHandler} [options.onPress=null] Event handler callback for {@link OpenSeadragon.Button.event:press}. + * @param {OpenSeadragon.EventHandler} [options.onRelease=null] Event handler callback for {@link OpenSeadragon.Button.event:release}. + * @param {OpenSeadragon.EventHandler} [options.onClick=null] Event handler callback for {@link OpenSeadragon.Button.event:click}. + * @param {OpenSeadragon.EventHandler} [options.onEnter=null] Event handler callback for {@link OpenSeadragon.Button.event:enter}. + * @param {OpenSeadragon.EventHandler} [options.onExit=null] Event handler callback for {@link OpenSeadragon.Button.event:exit}. + * @param {OpenSeadragon.EventHandler} [options.onFocus=null] Event handler callback for {@link OpenSeadragon.Button.event:focus}. + * @param {OpenSeadragon.EventHandler} [options.onBlur=null] Event handler callback for {@link OpenSeadragon.Button.event:blur}. + */ +$.Button = function( options ) { + + var _this = this; + + $.EventSource.call( this ); + + $.extend( true, this, { + + tooltip: null, + srcRest: null, + srcGroup: null, + srcHover: null, + srcDown: null, + clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold, + clickDistThreshold: $.DEFAULT_SETTINGS.clickDistThreshold, + /** + * How long to wait before fading. + * @member {Number} fadeDelay + * @memberof OpenSeadragon.Button# + */ + fadeDelay: 0, + /** + * How long should it take to fade the button. + * @member {Number} fadeLength + * @memberof OpenSeadragon.Button# + */ + fadeLength: 2000, + onPress: null, + onRelease: null, + onClick: null, + onEnter: null, + onExit: null, + onFocus: null, + onBlur: null + + }, options ); + + /** + * The button element. + * @member {Element} element + * @memberof OpenSeadragon.Button# + */ + this.element = options.element || $.makeNeutralElement("div"); + + //if the user has specified the element to bind the control to explicitly + //then do not add the default control images + if ( !options.element ) { + this.imgRest = $.makeTransparentImage( this.srcRest ); + this.imgGroup = $.makeTransparentImage( this.srcGroup ); + this.imgHover = $.makeTransparentImage( this.srcHover ); + this.imgDown = $.makeTransparentImage( this.srcDown ); + + this.imgRest.alt = + this.imgGroup.alt = + this.imgHover.alt = + this.imgDown.alt = + this.tooltip; + + this.element.style.position = "relative"; + $.setElementTouchActionNone( this.element ); + + this.imgGroup.style.position = + this.imgHover.style.position = + this.imgDown.style.position = + "absolute"; + + this.imgGroup.style.top = + this.imgHover.style.top = + this.imgDown.style.top = + "0px"; + + this.imgGroup.style.left = + this.imgHover.style.left = + this.imgDown.style.left = + "0px"; + + this.imgHover.style.visibility = + this.imgDown.style.visibility = + "hidden"; + + if ($.Browser.vendor == $.BROWSERS.FIREFOX && $.Browser.version < 3) { + this.imgGroup.style.top = + this.imgHover.style.top = + this.imgDown.style.top = + ""; + } + + this.element.appendChild( this.imgRest ); + this.element.appendChild( this.imgGroup ); + this.element.appendChild( this.imgHover ); + this.element.appendChild( this.imgDown ); + } + + + this.addHandler("press", this.onPress); + this.addHandler("release", this.onRelease); + this.addHandler("click", this.onClick); + this.addHandler("enter", this.onEnter); + this.addHandler("exit", this.onExit); + this.addHandler("focus", this.onFocus); + this.addHandler("blur", this.onBlur); + + /** + * The button's current state. + * @member {OpenSeadragon.ButtonState} currentState + * @memberof OpenSeadragon.Button# + */ + this.currentState = $.ButtonState.GROUP; + + // When the button last began to fade. + this.fadeBeginTime = null; + // Whether this button should fade after user stops interacting with the viewport. + this.shouldFade = false; + + this.element.style.display = "inline-block"; + this.element.style.position = "relative"; + this.element.title = this.tooltip; + + /** + * Tracks mouse/touch/key events on the button. + * @member {OpenSeadragon.MouseTracker} tracker + * @memberof OpenSeadragon.Button# + */ + this.tracker = new $.MouseTracker({ + + element: this.element, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + + enterHandler: function( event ) { + if ( event.insideElementPressed ) { + inTo( _this, $.ButtonState.DOWN ); + /** + * Raised when the cursor enters the Button element. + * + * @event enter + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( "enter", { originalEvent: event.originalEvent } ); + } else if ( !event.buttonDownAny ) { + inTo( _this, $.ButtonState.HOVER ); + } + }, + + focusHandler: function ( event ) { + this.enterHandler( event ); + /** + * Raised when the Button element receives focus. + * + * @event focus + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( "focus", { originalEvent: event.originalEvent } ); + }, + + exitHandler: function( event ) { + outTo( _this, $.ButtonState.GROUP ); + if ( event.insideElementPressed ) { + /** + * Raised when the cursor leaves the Button element. + * + * @event exit + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( "exit", { originalEvent: event.originalEvent } ); + } + }, + + blurHandler: function ( event ) { + this.exitHandler( event ); + /** + * Raised when the Button element loses focus. + * + * @event blur + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( "blur", { originalEvent: event.originalEvent } ); + }, + + pressHandler: function ( event ) { + inTo( _this, $.ButtonState.DOWN ); + /** + * Raised when a mouse button is pressed or touch occurs in the Button element. + * + * @event press + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( "press", { originalEvent: event.originalEvent } ); + }, + + releaseHandler: function( event ) { + if ( event.insideElementPressed && event.insideElementReleased ) { + outTo( _this, $.ButtonState.HOVER ); + /** + * Raised when the mouse button is released or touch ends in the Button element. + * + * @event release + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( "release", { originalEvent: event.originalEvent } ); + } else if ( event.insideElementPressed ) { + outTo( _this, $.ButtonState.GROUP ); + } else { + inTo( _this, $.ButtonState.HOVER ); + } + }, + + clickHandler: function( event ) { + if ( event.quick ) { + /** + * Raised when a mouse button is pressed and released or touch is initiated and ended in the Button element within the time and distance threshold. + * + * @event click + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent("click", { originalEvent: event.originalEvent }); + } + }, + + keyHandler: function( event ){ + //console.log( "%s : handling key %s!", _this.tooltip, event.keyCode); + if( 13 === event.keyCode ){ + /*** + * Raised when a mouse button is pressed and released or touch is initiated and ended in the Button element within the time and distance threshold. + * + * @event click + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( "click", { originalEvent: event.originalEvent } ); + /*** + * Raised when the mouse button is released or touch ends in the Button element. + * + * @event release + * @memberof OpenSeadragon.Button + * @type {object} + * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.raiseEvent( "release", { originalEvent: event.originalEvent } ); + return false; + } + return true; + } + + }); + + outTo( this, $.ButtonState.REST ); +}; + +$.extend( $.Button.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.Button.prototype */{ + + /** + * TODO: Determine what this function is intended to do and if it's actually + * useful as an API point. + * @function + */ + notifyGroupEnter: function() { + inTo( this, $.ButtonState.GROUP ); + }, + + /** + * TODO: Determine what this function is intended to do and if it's actually + * useful as an API point. + * @function + */ + notifyGroupExit: function() { + outTo( this, $.ButtonState.REST ); + }, + + /** + * @function + */ + disable: function(){ + this.notifyGroupExit(); + this.element.disabled = true; + $.setElementOpacity( this.element, 0.2, true ); + }, + + /** + * @function + */ + enable: function(){ + this.element.disabled = false; + $.setElementOpacity( this.element, 1.0, true ); + this.notifyGroupEnter(); + } + +}); + + +function scheduleFade( button ) { + $.requestAnimationFrame(function(){ + updateFade( button ); + }); +} + +function updateFade( button ) { + var currentTime, + deltaTime, + opacity; + + if ( button.shouldFade ) { + currentTime = $.now(); + deltaTime = currentTime - button.fadeBeginTime; + opacity = 1.0 - deltaTime / button.fadeLength; + opacity = Math.min( 1.0, opacity ); + opacity = Math.max( 0.0, opacity ); + + if( button.imgGroup ){ + $.setElementOpacity( button.imgGroup, opacity, true ); + } + if ( opacity > 0 ) { + // fade again + scheduleFade( button ); + } + } +} + +function beginFading( button ) { + button.shouldFade = true; + button.fadeBeginTime = $.now() + button.fadeDelay; + window.setTimeout( function(){ + scheduleFade( button ); + }, button.fadeDelay ); +} + +function stopFading( button ) { + button.shouldFade = false; + if( button.imgGroup ){ + $.setElementOpacity( button.imgGroup, 1.0, true ); + } +} + +function inTo( button, newState ) { + + if( button.element.disabled ){ + return; + } + + if ( newState >= $.ButtonState.GROUP && + button.currentState == $.ButtonState.REST ) { + stopFading( button ); + button.currentState = $.ButtonState.GROUP; + } + + if ( newState >= $.ButtonState.HOVER && + button.currentState == $.ButtonState.GROUP ) { + if( button.imgHover ){ + button.imgHover.style.visibility = ""; + } + button.currentState = $.ButtonState.HOVER; + } + + if ( newState >= $.ButtonState.DOWN && + button.currentState == $.ButtonState.HOVER ) { + if( button.imgDown ){ + button.imgDown.style.visibility = ""; + } + button.currentState = $.ButtonState.DOWN; + } +} + + +function outTo( button, newState ) { + + if( button.element.disabled ){ + return; + } + + if ( newState <= $.ButtonState.HOVER && + button.currentState == $.ButtonState.DOWN ) { + if( button.imgDown ){ + button.imgDown.style.visibility = "hidden"; + } + button.currentState = $.ButtonState.HOVER; + } + + if ( newState <= $.ButtonState.GROUP && + button.currentState == $.ButtonState.HOVER ) { + if( button.imgHover ){ + button.imgHover.style.visibility = "hidden"; + } + button.currentState = $.ButtonState.GROUP; + } + + if ( newState <= $.ButtonState.REST && + button.currentState == $.ButtonState.GROUP ) { + beginFading( button ); + button.currentState = $.ButtonState.REST; + } +} + + + +}( OpenSeadragon )); + +/* + * OpenSeadragon - ButtonGroup + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ +/** + * @class ButtonGroup + * @classdesc Manages events on groups of buttons. + * + * @memberof OpenSeadragon + * @param {Object} options - A dictionary of settings applied against the entire group of buttons. + * @param {Array} options.buttons Array of buttons + * @param {Element} [options.element] Element to use as the container + **/ +$.ButtonGroup = function( options ) { + + $.extend( true, this, { + /** + * An array containing the buttons themselves. + * @member {Array} buttons + * @memberof OpenSeadragon.ButtonGroup# + */ + buttons: [], + clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold, + clickDistThreshold: $.DEFAULT_SETTINGS.clickDistThreshold, + labelText: "" + }, options ); + + // copy the button elements TODO: Why? + var buttons = this.buttons.concat([]), + _this = this, + i; + + /** + * The shared container for the buttons. + * @member {Element} element + * @memberof OpenSeadragon.ButtonGroup# + */ + this.element = options.element || $.makeNeutralElement( "div" ); + + // TODO What if there IS an options.group specified? + if( !options.group ){ + this.label = $.makeNeutralElement( "label" ); + //TODO: support labels for ButtonGroups + //this.label.innerHTML = this.labelText; + this.element.style.display = "inline-block"; + this.element.appendChild( this.label ); + for ( i = 0; i < buttons.length; i++ ) { + this.element.appendChild( buttons[ i ].element ); + } + } + + $.setElementTouchActionNone( this.element ); + + /** + * Tracks mouse/touch/key events accross the group of buttons. + * @member {OpenSeadragon.MouseTracker} tracker + * @memberof OpenSeadragon.ButtonGroup# + */ + this.tracker = new $.MouseTracker({ + element: this.element, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + enterHandler: function ( event ) { + var i; + for ( i = 0; i < _this.buttons.length; i++ ) { + _this.buttons[ i ].notifyGroupEnter(); + } + }, + exitHandler: function ( event ) { + var i; + if ( !event.insideElementPressed ) { + for ( i = 0; i < _this.buttons.length; i++ ) { + _this.buttons[ i ].notifyGroupExit(); + } + } + }, + }); +}; + +/** @lends OpenSeadragon.ButtonGroup.prototype */ +$.ButtonGroup.prototype = { + + /** + * TODO: Figure out why this is used on the public API and if a more useful + * api can be created. + * @function + * @private + */ + emulateEnter: function() { + this.tracker.enterHandler( { eventSource: this.tracker } ); + }, + + /** + * TODO: Figure out why this is used on the public API and if a more useful + * api can be created. + * @function + * @private + */ + emulateExit: function() { + this.tracker.exitHandler( { eventSource: this.tracker } ); + } +}; + + +}( OpenSeadragon )); + +/* + * OpenSeadragon - Rect + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function($) { + +/** + * @class Rect + * @classdesc A Rectangle is described by it top left coordinates (x, y), width, + * height and degrees of rotation around (x, y). + * Note that the coordinate system used is the one commonly used with images: + * x increases when going to the right + * y increases when going to the bottom + * degrees increases clockwise with 0 being the horizontal + * + * The constructor normalizes the rectangle to always have 0 <= degrees < 90 + * + * @memberof OpenSeadragon + * @param {Number} [x=0] The vector component 'x'. + * @param {Number} [y=0] The vector component 'y'. + * @param {Number} [width=0] The vector component 'width'. + * @param {Number} [height=0] The vector component 'height'. + * @param {Number} [degrees=0] Rotation of the rectangle around (x,y) in degrees. + */ +$.Rect = function(x, y, width, height, degrees) { + /** + * The vector component 'x'. + * @member {Number} x + * @memberof OpenSeadragon.Rect# + */ + this.x = typeof(x) === "number" ? x : 0; + /** + * The vector component 'y'. + * @member {Number} y + * @memberof OpenSeadragon.Rect# + */ + this.y = typeof(y) === "number" ? y : 0; + /** + * The vector component 'width'. + * @member {Number} width + * @memberof OpenSeadragon.Rect# + */ + this.width = typeof(width) === "number" ? width : 0; + /** + * The vector component 'height'. + * @member {Number} height + * @memberof OpenSeadragon.Rect# + */ + this.height = typeof(height) === "number" ? height : 0; + + this.degrees = typeof(degrees) === "number" ? degrees : 0; + + // Normalizes the rectangle. + this.degrees = $.positiveModulo(this.degrees, 360); + var newTopLeft, newWidth; + if (this.degrees >= 270) { + newTopLeft = this.getTopRight(); + this.x = newTopLeft.x; + this.y = newTopLeft.y; + newWidth = this.height; + this.height = this.width; + this.width = newWidth; + this.degrees -= 270; + } else if (this.degrees >= 180) { + newTopLeft = this.getBottomRight(); + this.x = newTopLeft.x; + this.y = newTopLeft.y; + this.degrees -= 180; + } else if (this.degrees >= 90) { + newTopLeft = this.getBottomLeft(); + this.x = newTopLeft.x; + this.y = newTopLeft.y; + newWidth = this.height; + this.height = this.width; + this.width = newWidth; + this.degrees -= 90; + } +}; + +/** + * Builds a rectangle having the 3 specified points as summits. + * @static + * @memberof OpenSeadragon.Rect + * @param {OpenSeadragon.Point} topLeft + * @param {OpenSeadragon.Point} topRight + * @param {OpenSeadragon.Point} bottomLeft + * @returns {OpenSeadragon.Rect} + */ +$.Rect.fromSummits = function(topLeft, topRight, bottomLeft) { + var width = topLeft.distanceTo(topRight); + var height = topLeft.distanceTo(bottomLeft); + var diff = topRight.minus(topLeft); + var radians = Math.atan(diff.y / diff.x); + if (diff.x < 0) { + radians += Math.PI; + } else if (diff.y < 0) { + radians += 2 * Math.PI; + } + return new $.Rect( + topLeft.x, + topLeft.y, + width, + height, + radians / Math.PI * 180); +}; + +/** @lends OpenSeadragon.Rect.prototype */ +$.Rect.prototype = { + /** + * @function + * @returns {OpenSeadragon.Rect} a duplicate of this Rect + */ + clone: function() { + return new $.Rect( + this.x, + this.y, + this.width, + this.height, + this.degrees); + }, + + /** + * The aspect ratio is simply the ratio of width to height. + * @function + * @returns {Number} The ratio of width to height. + */ + getAspectRatio: function() { + return this.width / this.height; + }, + + /** + * Provides the coordinates of the upper-left corner of the rectangle as a + * point. + * @function + * @returns {OpenSeadragon.Point} The coordinate of the upper-left corner of + * the rectangle. + */ + getTopLeft: function() { + return new $.Point( + this.x, + this.y + ); + }, + + /** + * Provides the coordinates of the bottom-right corner of the rectangle as a + * point. + * @function + * @returns {OpenSeadragon.Point} The coordinate of the bottom-right corner of + * the rectangle. + */ + getBottomRight: function() { + return new $.Point(this.x + this.width, this.y + this.height) + .rotate(this.degrees, this.getTopLeft()); + }, + + /** + * Provides the coordinates of the top-right corner of the rectangle as a + * point. + * @function + * @returns {OpenSeadragon.Point} The coordinate of the top-right corner of + * the rectangle. + */ + getTopRight: function() { + return new $.Point(this.x + this.width, this.y) + .rotate(this.degrees, this.getTopLeft()); + }, + + /** + * Provides the coordinates of the bottom-left corner of the rectangle as a + * point. + * @function + * @returns {OpenSeadragon.Point} The coordinate of the bottom-left corner of + * the rectangle. + */ + getBottomLeft: function() { + return new $.Point(this.x, this.y + this.height) + .rotate(this.degrees, this.getTopLeft()); + }, + + /** + * Computes the center of the rectangle. + * @function + * @returns {OpenSeadragon.Point} The center of the rectangle as represented + * as represented by a 2-dimensional vector (x,y) + */ + getCenter: function() { + return new $.Point( + this.x + this.width / 2.0, + this.y + this.height / 2.0 + ).rotate(this.degrees, this.getTopLeft()); + }, + + /** + * Returns the width and height component as a vector OpenSeadragon.Point + * @function + * @returns {OpenSeadragon.Point} The 2 dimensional vector representing the + * the width and height of the rectangle. + */ + getSize: function() { + return new $.Point(this.width, this.height); + }, + + /** + * Determines if two Rectangles have equivalent components. + * @function + * @param {OpenSeadragon.Rect} rectangle The Rectangle to compare to. + * @return {Boolean} 'true' if all components are equal, otherwise 'false'. + */ + equals: function(other) { + return (other instanceof $.Rect) && + this.x === other.x && + this.y === other.y && + this.width === other.width && + this.height === other.height && + this.degrees === other.degrees; + }, + + /** + * Multiply all dimensions (except degrees) in this Rect by a factor and + * return a new Rect. + * @function + * @param {Number} factor The factor to multiply vector components. + * @returns {OpenSeadragon.Rect} A new rect representing the multiplication + * of the vector components by the factor + */ + times: function(factor) { + return new $.Rect( + this.x * factor, + this.y * factor, + this.width * factor, + this.height * factor, + this.degrees); + }, + + /** + * Translate/move this Rect by a vector and return new Rect. + * @function + * @param {OpenSeadragon.Point} delta The translation vector. + * @returns {OpenSeadragon.Rect} A new rect with altered position + */ + translate: function(delta) { + return new $.Rect( + this.x + delta.x, + this.y + delta.y, + this.width, + this.height, + this.degrees); + }, + + /** + * Returns the smallest rectangle that will contain this and the given + * rectangle bounding boxes. + * @param {OpenSeadragon.Rect} rect + * @return {OpenSeadragon.Rect} The new rectangle. + */ + union: function(rect) { + var thisBoundingBox = this.getBoundingBox(); + var otherBoundingBox = rect.getBoundingBox(); + + var left = Math.min(thisBoundingBox.x, otherBoundingBox.x); + var top = Math.min(thisBoundingBox.y, otherBoundingBox.y); + var right = Math.max( + thisBoundingBox.x + thisBoundingBox.width, + otherBoundingBox.x + otherBoundingBox.width); + var bottom = Math.max( + thisBoundingBox.y + thisBoundingBox.height, + otherBoundingBox.y + otherBoundingBox.height); + + return new $.Rect( + left, + top, + right - left, + bottom - top); + }, + + /** + * Returns the bounding box of the intersection of this rectangle with the + * given rectangle. + * @param {OpenSeadragon.Rect} rect + * @return {OpenSeadragon.Rect} the bounding box of the intersection + * or null if the rectangles don't intersect. + */ + intersection: function(rect) { + // Simplified version of Weiler Atherton clipping algorithm + // https://en.wikipedia.org/wiki/Weiler%E2%80%93Atherton_clipping_algorithm + // Because we just want the bounding box of the intersection, + // we can just compute the bounding box of: + // 1. all the summits of this which are inside rect + // 2. all the summits of rect which are inside this + // 3. all the intersections of rect and this + var EPSILON = 0.0000000001; + + var intersectionPoints = []; + + var thisTopLeft = this.getTopLeft(); + if (rect.containsPoint(thisTopLeft, EPSILON)) { + intersectionPoints.push(thisTopLeft); + } + var thisTopRight = this.getTopRight(); + if (rect.containsPoint(thisTopRight, EPSILON)) { + intersectionPoints.push(thisTopRight); + } + var thisBottomLeft = this.getBottomLeft(); + if (rect.containsPoint(thisBottomLeft, EPSILON)) { + intersectionPoints.push(thisBottomLeft); + } + var thisBottomRight = this.getBottomRight(); + if (rect.containsPoint(thisBottomRight, EPSILON)) { + intersectionPoints.push(thisBottomRight); + } + + var rectTopLeft = rect.getTopLeft(); + if (this.containsPoint(rectTopLeft, EPSILON)) { + intersectionPoints.push(rectTopLeft); + } + var rectTopRight = rect.getTopRight(); + if (this.containsPoint(rectTopRight, EPSILON)) { + intersectionPoints.push(rectTopRight); + } + var rectBottomLeft = rect.getBottomLeft(); + if (this.containsPoint(rectBottomLeft, EPSILON)) { + intersectionPoints.push(rectBottomLeft); + } + var rectBottomRight = rect.getBottomRight(); + if (this.containsPoint(rectBottomRight, EPSILON)) { + intersectionPoints.push(rectBottomRight); + } + + var thisSegments = this._getSegments(); + var rectSegments = rect._getSegments(); + for (var i = 0; i < thisSegments.length; i++) { + var thisSegment = thisSegments[i]; + for (var j = 0; j < rectSegments.length; j++) { + var rectSegment = rectSegments[j]; + var intersect = getIntersection(thisSegment[0], thisSegment[1], + rectSegment[0], rectSegment[1]); + if (intersect) { + intersectionPoints.push(intersect); + } + } + } + + // Get intersection point of segments [a,b] and [c,d] + function getIntersection(a, b, c, d) { + // http://stackoverflow.com/a/1968345/1440403 + var abVector = b.minus(a); + var cdVector = d.minus(c); + + var denom = -cdVector.x * abVector.y + abVector.x * cdVector.y; + if (denom === 0) { + return null; + } + + var s = (abVector.x * (a.y - c.y) - abVector.y * (a.x - c.x)) / denom; + var t = (cdVector.x * (a.y - c.y) - cdVector.y * (a.x - c.x)) / denom; + + if (-EPSILON <= s && s <= 1 - EPSILON && + -EPSILON <= t && t <= 1 - EPSILON) { + return new $.Point(a.x + t * abVector.x, a.y + t * abVector.y); + } + return null; + } + + if (intersectionPoints.length === 0) { + return null; + } + + var minX = intersectionPoints[0].x; + var maxX = intersectionPoints[0].x; + var minY = intersectionPoints[0].y; + var maxY = intersectionPoints[0].y; + for (var k = 1; k < intersectionPoints.length; k++) { + var point = intersectionPoints[k]; + if (point.x < minX) { + minX = point.x; + } + if (point.x > maxX) { + maxX = point.x; + } + if (point.y < minY) { + minY = point.y; + } + if (point.y > maxY) { + maxY = point.y; + } + } + return new $.Rect(minX, minY, maxX - minX, maxY - minY); + }, + + // private + _getSegments: function() { + var topLeft = this.getTopLeft(); + var topRight = this.getTopRight(); + var bottomLeft = this.getBottomLeft(); + var bottomRight = this.getBottomRight(); + return [[topLeft, topRight], + [topRight, bottomRight], + [bottomRight, bottomLeft], + [bottomLeft, topLeft]]; + }, + + /** + * Rotates a rectangle around a point. + * @function + * @param {Number} degrees The angle in degrees to rotate. + * @param {OpenSeadragon.Point} [pivot] The point about which to rotate. + * Defaults to the center of the rectangle. + * @return {OpenSeadragon.Rect} + */ + rotate: function(degrees, pivot) { + degrees = $.positiveModulo(degrees, 360); + if (degrees === 0) { + return this.clone(); + } + + pivot = pivot || this.getCenter(); + var newTopLeft = this.getTopLeft().rotate(degrees, pivot); + var newTopRight = this.getTopRight().rotate(degrees, pivot); + + var diff = newTopRight.minus(newTopLeft); + // Handle floating point error + diff = diff.apply(function(x) { + var EPSILON = 1e-15; + return Math.abs(x) < EPSILON ? 0 : x; + }); + var radians = Math.atan(diff.y / diff.x); + if (diff.x < 0) { + radians += Math.PI; + } else if (diff.y < 0) { + radians += 2 * Math.PI; + } + return new $.Rect( + newTopLeft.x, + newTopLeft.y, + this.width, + this.height, + radians / Math.PI * 180); + }, + + /** + * Retrieves the smallest horizontal (degrees=0) rectangle which contains + * this rectangle. + * @returns {OpenSeadragon.Rect} + */ + getBoundingBox: function() { + if (this.degrees === 0) { + return this.clone(); + } + var topLeft = this.getTopLeft(); + var topRight = this.getTopRight(); + var bottomLeft = this.getBottomLeft(); + var bottomRight = this.getBottomRight(); + var minX = Math.min(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x); + var maxX = Math.max(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x); + var minY = Math.min(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y); + var maxY = Math.max(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y); + return new $.Rect( + minX, + minY, + maxX - minX, + maxY - minY); + }, + + /** + * Retrieves the smallest horizontal (degrees=0) rectangle which contains + * this rectangle and has integers x, y, width and height + * @returns {OpenSeadragon.Rect} + */ + getIntegerBoundingBox: function() { + var boundingBox = this.getBoundingBox(); + var x = Math.floor(boundingBox.x); + var y = Math.floor(boundingBox.y); + var width = Math.ceil(boundingBox.width + boundingBox.x - x); + var height = Math.ceil(boundingBox.height + boundingBox.y - y); + return new $.Rect(x, y, width, height); + }, + + /** + * Determines whether a point is inside this rectangle (edge included). + * @function + * @param {OpenSeadragon.Point} point + * @param {Number} [epsilon=0] the margin of error allowed + * @returns {Boolean} true if the point is inside this rectangle, false + * otherwise. + */ + containsPoint: function(point, epsilon) { + epsilon = epsilon || 0; + + // See http://stackoverflow.com/a/2752754/1440403 for explanation + var topLeft = this.getTopLeft(); + var topRight = this.getTopRight(); + var bottomLeft = this.getBottomLeft(); + var topDiff = topRight.minus(topLeft); + var leftDiff = bottomLeft.minus(topLeft); + + return ((point.x - topLeft.x) * topDiff.x + + (point.y - topLeft.y) * topDiff.y >= -epsilon) && + + ((point.x - topRight.x) * topDiff.x + + (point.y - topRight.y) * topDiff.y <= epsilon) && + + ((point.x - topLeft.x) * leftDiff.x + + (point.y - topLeft.y) * leftDiff.y >= -epsilon) && + + ((point.x - bottomLeft.x) * leftDiff.x + + (point.y - bottomLeft.y) * leftDiff.y <= epsilon); + }, + + /** + * Provides a string representation of the rectangle which is useful for + * debugging. + * @function + * @returns {String} A string representation of the rectangle. + */ + toString: function() { + return "[" + + (Math.round(this.x * 100) / 100) + ", " + + (Math.round(this.y * 100) / 100) + ", " + + (Math.round(this.width * 100) / 100) + "x" + + (Math.round(this.height * 100) / 100) + ", " + + (Math.round(this.degrees * 100) / 100) + "deg" + + "]"; + } +}; + + +}(OpenSeadragon)); + +/* + * OpenSeadragon - ReferenceStrip + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function ( $ ) { + +// dictionary from id to private properties +var THIS = {}; + +/** + * The CollectionDrawer is a reimplementation if the Drawer API that + * focuses on allowing a viewport to be redefined as a collection + * of smaller viewports, defined by a clear number of rows and / or + * columns of which each item in the matrix of viewports has its own + * source. + * + * This idea is a reexpression of the idea of dzi collections + * which allows a clearer algorithm to reuse the tile sources already + * supported by OpenSeadragon, in heterogenious or homogenious + * sequences just like mixed groups already supported by the viewer + * for the purpose of image sequnces. + * + * TODO: The difficult part of this feature is figuring out how to express + * this functionality as a combination of the functionality already + * provided by Drawer, Viewport, TileSource, and Navigator. It may + * require better abstraction at those points in order to effeciently + * reuse those paradigms. + */ +/** + * @class ReferenceStrip + * @memberof OpenSeadragon + * @param {Object} options + */ +$.ReferenceStrip = function ( options ) { + + var _this = this, + viewer = options.viewer, + viewerSize = $.getElementSize( viewer.element ), + element, + style, + i; + + //We may need to create a new element and id if they did not + //provide the id for the existing element + if ( !options.id ) { + options.id = 'referencestrip-' + $.now(); + this.element = $.makeNeutralElement( "div" ); + this.element.id = options.id; + this.element.className = 'referencestrip'; + } + + options = $.extend( true, { + sizeRatio: $.DEFAULT_SETTINGS.referenceStripSizeRatio, + position: $.DEFAULT_SETTINGS.referenceStripPosition, + scroll: $.DEFAULT_SETTINGS.referenceStripScroll, + clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold + }, options, { + //required overrides + element: this.element, + //These need to be overridden to prevent recursion since + //the navigator is a viewer and a viewer has a navigator + showNavigator: false, + mouseNavEnabled: false, + showNavigationControl: false, + showSequenceControl: false + } ); + + $.extend( this, options ); + //Private state properties + THIS[this.id] = { + "animating": false + }; + + this.minPixelRatio = this.viewer.minPixelRatio; + + style = this.element.style; + style.marginTop = '0px'; + style.marginRight = '0px'; + style.marginBottom = '0px'; + style.marginLeft = '0px'; + style.left = '0px'; + style.bottom = '0px'; + style.border = '0px'; + style.background = '#000'; + style.position = 'relative'; + + $.setElementTouchActionNone( this.element ); + + $.setElementOpacity( this.element, 0.8 ); + + this.viewer = viewer; + this.innerTracker = new $.MouseTracker( { + element: this.element, + dragHandler: $.delegate( this, onStripDrag ), + scrollHandler: $.delegate( this, onStripScroll ), + enterHandler: $.delegate( this, onStripEnter ), + exitHandler: $.delegate( this, onStripExit ), + keyDownHandler: $.delegate( this, onKeyDown ), + keyHandler: $.delegate( this, onKeyPress ) + } ); + + //Controls the position and orientation of the reference strip and sets the + //appropriate width and height + if ( options.width && options.height ) { + this.element.style.width = options.width + 'px'; + this.element.style.height = options.height + 'px'; + viewer.addControl( + this.element, + { anchor: $.ControlAnchor.BOTTOM_LEFT } + ); + } else { + if ( "horizontal" == options.scroll ) { + this.element.style.width = ( + viewerSize.x * + options.sizeRatio * + viewer.tileSources.length + ) + ( 12 * viewer.tileSources.length ) + 'px'; + + this.element.style.height = ( + viewerSize.y * + options.sizeRatio + ) + 'px'; + + viewer.addControl( + this.element, + { anchor: $.ControlAnchor.BOTTOM_LEFT } + ); + } else { + this.element.style.height = ( + viewerSize.y * + options.sizeRatio * + viewer.tileSources.length + ) + ( 12 * viewer.tileSources.length ) + 'px'; + + this.element.style.width = ( + viewerSize.x * + options.sizeRatio + ) + 'px'; + + viewer.addControl( + this.element, + { anchor: $.ControlAnchor.TOP_LEFT } + ); + + } + } + + this.panelWidth = ( viewerSize.x * this.sizeRatio ) + 8; + this.panelHeight = ( viewerSize.y * this.sizeRatio ) + 8; + this.panels = []; + this.miniViewers = {}; + + /*jshint loopfunc:true*/ + for ( i = 0; i < viewer.tileSources.length; i++ ) { + + element = $.makeNeutralElement( 'div' ); + element.id = this.element.id + "-" + i; + + element.style.width = _this.panelWidth + 'px'; + element.style.height = _this.panelHeight + 'px'; + element.style.display = 'inline'; + element.style.float = 'left'; //Webkit + element.style.cssFloat = 'left'; //Firefox + element.style.styleFloat = 'left'; //IE + element.style.padding = '2px'; + $.setElementTouchActionNone( element ); + + element.innerTracker = new $.MouseTracker( { + element: element, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + pressHandler: function ( event ) { + event.eventSource.dragging = $.now(); + }, + releaseHandler: function ( event ) { + var tracker = event.eventSource, + id = tracker.element.id, + page = Number( id.split( '-' )[2] ), + now = $.now(); + + if ( event.insideElementPressed && + event.insideElementReleased && + tracker.dragging && + ( now - tracker.dragging ) < tracker.clickTimeThreshold ) { + tracker.dragging = null; + viewer.goToPage( page ); + } + } + } ); + + this.element.appendChild( element ); + + element.activePanel = false; + + this.panels.push( element ); + + } + loadPanels( this, this.scroll == 'vertical' ? viewerSize.y : viewerSize.x, 0 ); + this.setFocus( 0 ); + +}; + +$.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.ReferenceStrip.prototype */{ + + /** + * @function + */ + setFocus: function ( page ) { + var element = $.getElement( this.element.id + '-' + page ), + viewerSize = $.getElementSize( this.viewer.canvas ), + scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ), + scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ), + offsetLeft = -Number( this.element.style.marginLeft.replace( 'px', '' ) ), + offsetTop = -Number( this.element.style.marginTop.replace( 'px', '' ) ), + offset; + + if ( this.currentSelected !== element ) { + if ( this.currentSelected ) { + this.currentSelected.style.background = '#000'; + } + this.currentSelected = element; + this.currentSelected.style.background = '#999'; + + if ( 'horizontal' == this.scroll ) { + //right left + offset = ( Number( page ) ) * ( this.panelWidth + 3 ); + if ( offset > offsetLeft + viewerSize.x - this.panelWidth ) { + offset = Math.min( offset, ( scrollWidth - viewerSize.x ) ); + this.element.style.marginLeft = -offset + 'px'; + loadPanels( this, viewerSize.x, -offset ); + } else if ( offset < offsetLeft ) { + offset = Math.max( 0, offset - viewerSize.x / 2 ); + this.element.style.marginLeft = -offset + 'px'; + loadPanels( this, viewerSize.x, -offset ); + } + } else { + offset = ( Number( page ) ) * ( this.panelHeight + 3 ); + if ( offset > offsetTop + viewerSize.y - this.panelHeight ) { + offset = Math.min( offset, ( scrollHeight - viewerSize.y ) ); + this.element.style.marginTop = -offset + 'px'; + loadPanels( this, viewerSize.y, -offset ); + } else if ( offset < offsetTop ) { + offset = Math.max( 0, offset - viewerSize.y / 2 ); + this.element.style.marginTop = -offset + 'px'; + loadPanels( this, viewerSize.y, -offset ); + } + } + + this.currentPage = page; + onStripEnter.call( this, { eventSource: this.innerTracker } ); + } + }, + + /** + * @function + */ + update: function () { + if ( THIS[this.id].animating ) { + $.console.log( 'image reference strip update' ); + return true; + } + return false; + }, + + // Overrides Viewer.destroy + destroy: function() { + if (this.miniViewers) { + for (var key in this.miniViewers) { + this.miniViewers[key].destroy(); + } + } + + if (this.element) { + this.element.parentNode.removeChild(this.element); + } + } + +} ); + + + + +/** + * @private + * @inner + * @function + */ +function onStripDrag( event ) { + + var offsetLeft = Number( this.element.style.marginLeft.replace( 'px', '' ) ), + offsetTop = Number( this.element.style.marginTop.replace( 'px', '' ) ), + scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ), + scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ), + viewerSize = $.getElementSize( this.viewer.canvas ); + this.dragging = true; + if ( this.element ) { + if ( 'horizontal' == this.scroll ) { + if ( -event.delta.x > 0 ) { + //forward + if ( offsetLeft > -( scrollWidth - viewerSize.x ) ) { + this.element.style.marginLeft = ( offsetLeft + ( event.delta.x * 2 ) ) + 'px'; + loadPanels( this, viewerSize.x, offsetLeft + ( event.delta.x * 2 ) ); + } + } else if ( -event.delta.x < 0 ) { + //reverse + if ( offsetLeft < 0 ) { + this.element.style.marginLeft = ( offsetLeft + ( event.delta.x * 2 ) ) + 'px'; + loadPanels( this, viewerSize.x, offsetLeft + ( event.delta.x * 2 ) ); + } + } + } else { + if ( -event.delta.y > 0 ) { + //forward + if ( offsetTop > -( scrollHeight - viewerSize.y ) ) { + this.element.style.marginTop = ( offsetTop + ( event.delta.y * 2 ) ) + 'px'; + loadPanels( this, viewerSize.y, offsetTop + ( event.delta.y * 2 ) ); + } + } else if ( -event.delta.y < 0 ) { + //reverse + if ( offsetTop < 0 ) { + this.element.style.marginTop = ( offsetTop + ( event.delta.y * 2 ) ) + 'px'; + loadPanels( this, viewerSize.y, offsetTop + ( event.delta.y * 2 ) ); + } + } + } + } + return false; + +} + + + +/** + * @private + * @inner + * @function + */ +function onStripScroll( event ) { + var offsetLeft = Number( this.element.style.marginLeft.replace( 'px', '' ) ), + offsetTop = Number( this.element.style.marginTop.replace( 'px', '' ) ), + scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ), + scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ), + viewerSize = $.getElementSize( this.viewer.canvas ); + if ( this.element ) { + if ( 'horizontal' == this.scroll ) { + if ( event.scroll > 0 ) { + //forward + if ( offsetLeft > -( scrollWidth - viewerSize.x ) ) { + this.element.style.marginLeft = ( offsetLeft - ( event.scroll * 60 ) ) + 'px'; + loadPanels( this, viewerSize.x, offsetLeft - ( event.scroll * 60 ) ); + } + } else if ( event.scroll < 0 ) { + //reverse + if ( offsetLeft < 0 ) { + this.element.style.marginLeft = ( offsetLeft - ( event.scroll * 60 ) ) + 'px'; + loadPanels( this, viewerSize.x, offsetLeft - ( event.scroll * 60 ) ); + } + } + } else { + if ( event.scroll < 0 ) { + //scroll up + if ( offsetTop > viewerSize.y - scrollHeight ) { + this.element.style.marginTop = ( offsetTop + ( event.scroll * 60 ) ) + 'px'; + loadPanels( this, viewerSize.y, offsetTop + ( event.scroll * 60 ) ); + } + } else if ( event.scroll > 0 ) { + //scroll dowm + if ( offsetTop < 0 ) { + this.element.style.marginTop = ( offsetTop + ( event.scroll * 60 ) ) + 'px'; + loadPanels( this, viewerSize.y, offsetTop + ( event.scroll * 60 ) ); + } + } + } + } + //cancels event + return false; +} + + +function loadPanels( strip, viewerSize, scroll ) { + var panelSize, + activePanelsStart, + activePanelsEnd, + miniViewer, + style, + i, + element; + if ( 'horizontal' == strip.scroll ) { + panelSize = strip.panelWidth; + } else { + panelSize = strip.panelHeight; + } + activePanelsStart = Math.ceil( viewerSize / panelSize ) + 5; + activePanelsEnd = Math.ceil( ( Math.abs( scroll ) + viewerSize ) / panelSize ) + 1; + activePanelsStart = activePanelsEnd - activePanelsStart; + activePanelsStart = activePanelsStart < 0 ? 0 : activePanelsStart; + + for ( i = activePanelsStart; i < activePanelsEnd && i < strip.panels.length; i++ ) { + element = strip.panels[i]; + if ( !element.activePanel ) { + var miniTileSource; + var originalTileSource = strip.viewer.tileSources[i]; + if (originalTileSource.referenceStripThumbnailUrl) { + miniTileSource = { + type: 'image', + url: originalTileSource.referenceStripThumbnailUrl + }; + } else { + miniTileSource = originalTileSource; + } + miniViewer = new $.Viewer( { + id: element.id, + tileSources: [miniTileSource], + element: element, + navigatorSizeRatio: strip.sizeRatio, + showNavigator: false, + mouseNavEnabled: false, + showNavigationControl: false, + showSequenceControl: false, + immediateRender: true, + blendTime: 0, + animationTime: 0 + } ); + + miniViewer.displayRegion = $.makeNeutralElement( "div" ); + miniViewer.displayRegion.id = element.id + '-displayregion'; + miniViewer.displayRegion.className = 'displayregion'; + + style = miniViewer.displayRegion.style; + style.position = 'relative'; + style.top = '0px'; + style.left = '0px'; + style.fontSize = '0px'; + style.overflow = 'hidden'; + style.float = 'left'; //Webkit + style.cssFloat = 'left'; //Firefox + style.styleFloat = 'left'; //IE + style.zIndex = 999999999; + style.cursor = 'default'; + style.width = ( strip.panelWidth - 4 ) + 'px'; + style.height = ( strip.panelHeight - 4 ) + 'px'; + + // TODO: What is this for? Future keyboard navigation support? + miniViewer.displayRegion.innerTracker = new $.MouseTracker( { + element: miniViewer.displayRegion, + startDisabled: true + } ); + + element.getElementsByTagName( 'div' )[0].appendChild( + miniViewer.displayRegion + ); + + strip.miniViewers[element.id] = miniViewer; + + element.activePanel = true; + } + } +} + + +/** + * @private + * @inner + * @function + */ +function onStripEnter( event ) { + var element = event.eventSource.element; + + //$.setElementOpacity(element, 0.8); + + //element.style.border = '1px solid #555'; + //element.style.background = '#000'; + + if ( 'horizontal' == this.scroll ) { + + //element.style.paddingTop = "0px"; + element.style.marginBottom = "0px"; + + } else { + + //element.style.paddingRight = "0px"; + element.style.marginLeft = "0px"; + + } + return false; +} + + +/** + * @private + * @inner + * @function + */ +function onStripExit( event ) { + var element = event.eventSource.element; + + if ( 'horizontal' == this.scroll ) { + + //element.style.paddingTop = "10px"; + element.style.marginBottom = "-" + ( $.getElementSize( element ).y / 2 ) + "px"; + + } else { + + //element.style.paddingRight = "10px"; + element.style.marginLeft = "-" + ( $.getElementSize( element ).x / 2 ) + "px"; + + } + return false; +} + + +/** + * @private + * @inner + * @function + */ +function onKeyDown( event ) { + //console.log( event.keyCode ); + + if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { + switch ( event.keyCode ) { + case 38: //up arrow + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); + return false; + case 40: //down arrow + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); + return false; + case 37: //left arrow + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); + return false; + case 39: //right arrow + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); + return false; + default: + //console.log( 'navigator keycode %s', event.keyCode ); + return true; + } + } else { + return true; + } +} + + +/** + * @private + * @inner + * @function + */ +function onKeyPress( event ) { + //console.log( event.keyCode ); + + if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { + switch ( event.keyCode ) { + case 61: //=|+ + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); + return false; + case 45: //-|_ + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); + return false; + case 48: //0|) + case 119: //w + case 87: //W + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); + return false; + case 115: //s + case 83: //S + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); + return false; + case 97: //a + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); + return false; + case 100: //d + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); + return false; + default: + //console.log( 'navigator keycode %s', event.keyCode ); + return true; + } + } else { + return true; + } +} + +}(OpenSeadragon)); + +/* + * OpenSeadragon - DisplayRect + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class DisplayRect + * @classdesc A display rectangle is very similar to {@link OpenSeadragon.Rect} but adds two + * fields, 'minLevel' and 'maxLevel' which denote the supported zoom levels + * for this rectangle. + * + * @memberof OpenSeadragon + * @extends OpenSeadragon.Rect + * @param {Number} x The vector component 'x'. + * @param {Number} y The vector component 'y'. + * @param {Number} width The vector component 'height'. + * @param {Number} height The vector component 'width'. + * @param {Number} minLevel The lowest zoom level supported. + * @param {Number} maxLevel The highest zoom level supported. + */ +$.DisplayRect = function( x, y, width, height, minLevel, maxLevel ) { + $.Rect.apply( this, [ x, y, width, height ] ); + + /** + * The lowest zoom level supported. + * @member {Number} minLevel + * @memberof OpenSeadragon.DisplayRect# + */ + this.minLevel = minLevel; + /** + * The highest zoom level supported. + * @member {Number} maxLevel + * @memberof OpenSeadragon.DisplayRect# + */ + this.maxLevel = maxLevel; +}; + +$.extend( $.DisplayRect.prototype, $.Rect.prototype ); + +}( OpenSeadragon )); + +/* + * OpenSeadragon - Spring + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class Spring + * @memberof OpenSeadragon + * @param {Object} options - Spring configuration settings. + * @param {Number} options.springStiffness - Spring stiffness. Must be greater than zero. + * The closer to zero, the closer to linear animation. + * @param {Number} options.animationTime - Animation duration per spring, in seconds. + * Must be zero or greater. + * @param {Number} [options.initial=0] - Initial value of spring. + * @param {Boolean} [options.exponential=false] - Whether this spring represents + * an exponential scale (such as zoom) and should be animated accordingly. Note that + * exponential springs must have non-zero values. + */ +$.Spring = function( options ) { + var args = arguments; + + if( typeof( options ) != 'object' ){ + //allows backward compatible use of ( initialValue, config ) as + //constructor parameters + options = { + initial: args.length && typeof ( args[ 0 ] ) == "number" ? + args[ 0 ] : + undefined, + /** + * Spring stiffness. + * @member {Number} springStiffness + * @memberof OpenSeadragon.Spring# + */ + springStiffness: args.length > 1 ? + args[ 1 ].springStiffness : + 5.0, + /** + * Animation duration per spring. + * @member {Number} animationTime + * @memberof OpenSeadragon.Spring# + */ + animationTime: args.length > 1 ? + args[ 1 ].animationTime : + 1.5 + }; + } + + $.console.assert(typeof options.springStiffness === "number" && options.springStiffness !== 0, + "[OpenSeadragon.Spring] options.springStiffness must be a non-zero number"); + + $.console.assert(typeof options.animationTime === "number" && options.animationTime >= 0, + "[OpenSeadragon.Spring] options.animationTime must be a number greater than or equal to 0"); + + if (options.exponential) { + this._exponential = true; + delete options.exponential; + } + + $.extend( true, this, options); + + /** + * @member {Object} current + * @memberof OpenSeadragon.Spring# + * @property {Number} value + * @property {Number} time + */ + this.current = { + value: typeof ( this.initial ) == "number" ? + this.initial : + (this._exponential ? 0 : 1), + time: $.now() // always work in milliseconds + }; + + $.console.assert(!this._exponential || this.current.value !== 0, + "[OpenSeadragon.Spring] value must be non-zero for exponential springs"); + + /** + * @member {Object} start + * @memberof OpenSeadragon.Spring# + * @property {Number} value + * @property {Number} time + */ + this.start = { + value: this.current.value, + time: this.current.time + }; + + /** + * @member {Object} target + * @memberof OpenSeadragon.Spring# + * @property {Number} value + * @property {Number} time + */ + this.target = { + value: this.current.value, + time: this.current.time + }; + + if (this._exponential) { + this.start._logValue = Math.log(this.start.value); + this.target._logValue = Math.log(this.target.value); + this.current._logValue = Math.log(this.current.value); + } +}; + +/** @lends OpenSeadragon.Spring.prototype */ +$.Spring.prototype = { + + /** + * @function + * @param {Number} target + */ + resetTo: function( target ) { + $.console.assert(!this._exponential || target !== 0, + "[OpenSeadragon.Spring.resetTo] target must be non-zero for exponential springs"); + + this.start.value = this.target.value = this.current.value = target; + this.start.time = this.target.time = this.current.time = $.now(); + + if (this._exponential) { + this.start._logValue = Math.log(this.start.value); + this.target._logValue = Math.log(this.target.value); + this.current._logValue = Math.log(this.current.value); + } + }, + + /** + * @function + * @param {Number} target + */ + springTo: function( target ) { + $.console.assert(!this._exponential || target !== 0, + "[OpenSeadragon.Spring.springTo] target must be non-zero for exponential springs"); + + this.start.value = this.current.value; + this.start.time = this.current.time; + this.target.value = target; + this.target.time = this.start.time + 1000 * this.animationTime; + + if (this._exponential) { + this.start._logValue = Math.log(this.start.value); + this.target._logValue = Math.log(this.target.value); + } + }, + + /** + * @function + * @param {Number} delta + */ + shiftBy: function( delta ) { + this.start.value += delta; + this.target.value += delta; + + if (this._exponential) { + $.console.assert(this.target.value !== 0 && this.start.value !== 0, + "[OpenSeadragon.Spring.shiftBy] spring value must be non-zero for exponential springs"); + + this.start._logValue = Math.log(this.start.value); + this.target._logValue = Math.log(this.target.value); + } + }, + + setExponential: function(value) { + this._exponential = value; + + if (this._exponential) { + $.console.assert(this.current.value !== 0 && this.target.value !== 0 && this.start.value !== 0, + "[OpenSeadragon.Spring.setExponential] spring value must be non-zero for exponential springs"); + + this.start._logValue = Math.log(this.start.value); + this.target._logValue = Math.log(this.target.value); + this.current._logValue = Math.log(this.current.value); + } + }, + + /** + * @function + * @returns true if the value got updated, false otherwise + */ + update: function() { + this.current.time = $.now(); + + var startValue, targetValue; + if (this._exponential) { + startValue = this.start._logValue; + targetValue = this.target._logValue; + } else { + startValue = this.start.value; + targetValue = this.target.value; + } + + var currentValue = (this.current.time >= this.target.time) ? + targetValue : + startValue + + ( targetValue - startValue ) * + transform( + this.springStiffness, + ( this.current.time - this.start.time ) / + ( this.target.time - this.start.time ) + ); + + var oldValue = this.current.value; + if (this._exponential) { + this.current.value = Math.exp(currentValue); + } else { + this.current.value = currentValue; + } + + return oldValue != this.current.value; + }, + + /** + * Returns whether the spring is at the target value + * @function + * @returns {Boolean} True if at target value, false otherwise + */ + isAtTargetValue: function() { + return this.current.value === this.target.value; + } +}; + +/** + * @private + */ +function transform( stiffness, x ) { + return ( 1.0 - Math.exp( stiffness * -x ) ) / + ( 1.0 - Math.exp( -stiffness ) ); +} + +}( OpenSeadragon )); + +/* + * OpenSeadragon - ImageLoader + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function($){ + +/** + * @private + * @class ImageJob + * @classdesc Handles downloading of a single image. + * @param {Object} options - Options for this ImageJob. + * @param {String} [options.src] - URL of image to download. + * @param {String} [options.loadWithAjax] - Whether to load this image with AJAX. + * @param {String} [options.ajaxHeaders] - Headers to add to the image request if using AJAX. + * @param {String} [options.crossOriginPolicy] - CORS policy to use for downloads + * @param {Function} [options.callback] - Called once image has been downloaded. + * @param {Function} [options.abort] - Called when this image job is aborted. + * @param {Number} [options.timeout] - The max number of milliseconds that this image job may take to complete. + */ +function ImageJob (options) { + + $.extend(true, this, { + timeout: $.DEFAULT_SETTINGS.timeout, + jobId: null + }, options); + + /** + * Image object which will contain downloaded image. + * @member {Image} image + * @memberof OpenSeadragon.ImageJob# + */ + this.image = null; +} + +ImageJob.prototype = { + errorMsg: null, + + /** + * Starts the image job. + * @method + */ + start: function(){ + var self = this; + var selfAbort = this.abort; + + this.image = new Image(); + + this.image.onload = function(){ + self.finish(true); + }; + this.image.onabort = this.image.onerror = function() { + self.errorMsg = "Image load aborted"; + self.finish(false); + }; + + this.jobId = window.setTimeout(function(){ + self.errorMsg = "Image load exceeded timeout"; + self.finish(false); + }, this.timeout); + + // Load the tile with an AJAX request if the loadWithAjax option is + // set. Otherwise load the image by setting the source proprety of the image object. + if (this.loadWithAjax) { + this.request = $.makeAjaxRequest({ + url: this.src, + withCredentials: this.ajaxWithCredentials, + headers: this.ajaxHeaders, + responseType: "arraybuffer", + success: function(request) { + var blb; + // Make the raw data into a blob. + // BlobBuilder fallback adapted from + // http://stackoverflow.com/questions/15293694/blob-constructor-browser-compatibility + try { + blb = new window.Blob([request.response]); + } catch (e) { + var BlobBuilder = ( + window.BlobBuilder || + window.WebKitBlobBuilder || + window.MozBlobBuilder || + window.MSBlobBuilder + ); + if (e.name === 'TypeError' && BlobBuilder) { + var bb = new BlobBuilder(); + bb.append(request.response); + blb = bb.getBlob(); + } + } + // If the blob is empty for some reason consider the image load a failure. + if (blb.size === 0) { + self.errorMsg = "Empty image response."; + self.finish(false); + } + // Create a URL for the blob data and make it the source of the image object. + // This will still trigger Image.onload to indicate a successful tile load. + var url = (window.URL || window.webkitURL).createObjectURL(blb); + self.image.src = url; + }, + error: function(request) { + self.errorMsg = "Image load aborted - XHR error"; + self.finish(false); + } + }); + + // Provide a function to properly abort the request. + this.abort = function() { + self.request.abort(); + + // Call the existing abort function if available + if (typeof selfAbort === "function") { + selfAbort(); + } + }; + } else { + if (this.crossOriginPolicy !== false) { + this.image.crossOrigin = this.crossOriginPolicy; + } + + this.image.src = this.src; + } + }, + + finish: function(successful) { + this.image.onload = this.image.onerror = this.image.onabort = null; + if (!successful) { + this.image = null; + } + + if (this.jobId) { + window.clearTimeout(this.jobId); + } + + this.callback(this); + } + +}; + +/** + * @class ImageLoader + * @memberof OpenSeadragon + * @classdesc Handles downloading of a set of images using asynchronous queue pattern. + * You generally won't have to interact with the ImageLoader directly. + * @param {Object} options - Options for this ImageLoader. + * @param {Number} [options.jobLimit] - The number of concurrent image requests. See imageLoaderLimit in {@link OpenSeadragon.Options} for details. + * @param {Number} [options.timeout] - The max number of milliseconds that an image job may take to complete. + */ +$.ImageLoader = function(options) { + + $.extend(true, this, { + jobLimit: $.DEFAULT_SETTINGS.imageLoaderLimit, + timeout: $.DEFAULT_SETTINGS.timeout, + jobQueue: [], + jobsInProgress: 0 + }, options); + +}; + +/** @lends OpenSeadragon.ImageLoader.prototype */ +$.ImageLoader.prototype = { + + /** + * Add an unloaded image to the loader queue. + * @method + * @param {Object} options - Options for this job. + * @param {String} [options.src] - URL of image to download. + * @param {String} [options.loadWithAjax] - Whether to load this image with AJAX. + * @param {String} [options.ajaxHeaders] - Headers to add to the image request if using AJAX. + * @param {String|Boolean} [options.crossOriginPolicy] - CORS policy to use for downloads + * @param {Boolean} [options.ajaxWithCredentials] - Whether to set withCredentials on AJAX + * requests. + * @param {Function} [options.callback] - Called once image has been downloaded. + * @param {Function} [options.abort] - Called when this image job is aborted. + */ + addJob: function(options) { + var _this = this, + complete = function(job) { + completeJob(_this, job, options.callback); + }, + jobOptions = { + src: options.src, + loadWithAjax: options.loadWithAjax, + ajaxHeaders: options.loadWithAjax ? options.ajaxHeaders : null, + crossOriginPolicy: options.crossOriginPolicy, + ajaxWithCredentials: options.ajaxWithCredentials, + callback: complete, + abort: options.abort, + timeout: this.timeout + }, + newJob = new ImageJob(jobOptions); + + if ( !this.jobLimit || this.jobsInProgress < this.jobLimit ) { + newJob.start(); + this.jobsInProgress++; + } + else { + this.jobQueue.push( newJob ); + } + }, + + /** + * Clear any unstarted image loading jobs from the queue. + * @method + */ + clear: function() { + for( var i = 0; i < this.jobQueue.length; i++ ) { + var job = this.jobQueue[i]; + if ( typeof job.abort === "function" ) { + job.abort(); + } + } + + this.jobQueue = []; + } +}; + +/** + * Cleans up ImageJob once completed. + * @method + * @private + * @param loader - ImageLoader used to start job. + * @param job - The ImageJob that has completed. + * @param callback - Called once cleanup is finished. + */ +function completeJob(loader, job, callback) { + var nextJob; + + loader.jobsInProgress--; + + if ((!loader.jobLimit || loader.jobsInProgress < loader.jobLimit) && loader.jobQueue.length > 0) { + nextJob = loader.jobQueue.shift(); + nextJob.start(); + loader.jobsInProgress++; + } + + callback(job.image, job.errorMsg, job.request); +} + +}(OpenSeadragon)); + +/* + * OpenSeadragon - Tile + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class Tile + * @memberof OpenSeadragon + * @param {Number} level The zoom level this tile belongs to. + * @param {Number} x The vector component 'x'. + * @param {Number} y The vector component 'y'. + * @param {OpenSeadragon.Point} bounds Where this tile fits, in normalized + * coordinates. + * @param {Boolean} exists Is this tile a part of a sparse image? ( Also has + * this tile failed to load? ) + * @param {String} url The URL of this tile's image. + * @param {CanvasRenderingContext2D} context2D The context2D of this tile if it + * is provided directly by the tile source. + * @param {Boolean} loadWithAjax Whether this tile image should be loaded with an AJAX request . + * @param {Object} ajaxHeaders The headers to send with this tile's AJAX request (if applicable). + */ +$.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, ajaxHeaders) { + /** + * The zoom level this tile belongs to. + * @member {Number} level + * @memberof OpenSeadragon.Tile# + */ + this.level = level; + /** + * The vector component 'x'. + * @member {Number} x + * @memberof OpenSeadragon.Tile# + */ + this.x = x; + /** + * The vector component 'y'. + * @member {Number} y + * @memberof OpenSeadragon.Tile# + */ + this.y = y; + /** + * Where this tile fits, in normalized coordinates + * @member {OpenSeadragon.Rect} bounds + * @memberof OpenSeadragon.Tile# + */ + this.bounds = bounds; + /** + * Is this tile a part of a sparse image? Also has this tile failed to load? + * @member {Boolean} exists + * @memberof OpenSeadragon.Tile# + */ + this.exists = exists; + /** + * The URL of this tile's image. + * @member {String} url + * @memberof OpenSeadragon.Tile# + */ + this.url = url; + /** + * The context2D of this tile if it is provided directly by the tile source. + * @member {CanvasRenderingContext2D} context2D + * @memberOf OpenSeadragon.Tile# + */ + this.context2D = context2D; + /** + * Whether to load this tile's image with an AJAX request. + * @member {Boolean} loadWithAjax + * @memberof OpenSeadragon.Tile# + */ + this.loadWithAjax = loadWithAjax; + /** + * The headers to be used in requesting this tile's image. + * Only used if loadWithAjax is set to true. + * @member {Object} ajaxHeaders + * @memberof OpenSeadragon.Tile# + */ + this.ajaxHeaders = ajaxHeaders; + /** + * The unique cache key for this tile. + * @member {String} cacheKey + * @memberof OpenSeadragon.Tile# + */ + if (this.ajaxHeaders) { + this.cacheKey = this.url + "+" + JSON.stringify(this.ajaxHeaders); + } else { + this.cacheKey = this.url; + } + /** + * Is this tile loaded? + * @member {Boolean} loaded + * @memberof OpenSeadragon.Tile# + */ + this.loaded = false; + /** + * Is this tile loading? + * @member {Boolean} loading + * @memberof OpenSeadragon.Tile# + */ + this.loading = false; + + /** + * The HTML div element for this tile + * @member {Element} element + * @memberof OpenSeadragon.Tile# + */ + this.element = null; + /** + * The HTML img element for this tile. + * @member {Element} imgElement + * @memberof OpenSeadragon.Tile# + */ + this.imgElement = null; + /** + * The Image object for this tile. + * @member {Object} image + * @memberof OpenSeadragon.Tile# + */ + this.image = null; + + /** + * The alias of this.element.style. + * @member {String} style + * @memberof OpenSeadragon.Tile# + */ + this.style = null; + /** + * This tile's position on screen, in pixels. + * @member {OpenSeadragon.Point} position + * @memberof OpenSeadragon.Tile# + */ + this.position = null; + /** + * This tile's size on screen, in pixels. + * @member {OpenSeadragon.Point} size + * @memberof OpenSeadragon.Tile# + */ + this.size = null; + /** + * The start time of this tile's blending. + * @member {Number} blendStart + * @memberof OpenSeadragon.Tile# + */ + this.blendStart = null; + /** + * The current opacity this tile should be. + * @member {Number} opacity + * @memberof OpenSeadragon.Tile# + */ + this.opacity = null; + /** + * The squared distance of this tile to the viewport center. + * Use for comparing tiles. + * @private + * @member {Number} squaredDistance + * @memberof OpenSeadragon.Tile# + */ + this.squaredDistance = null; + /** + * The visibility score of this tile. + * @member {Number} visibility + * @memberof OpenSeadragon.Tile# + */ + this.visibility = null; + + /** + * Whether this tile is currently being drawn. + * @member {Boolean} beingDrawn + * @memberof OpenSeadragon.Tile# + */ + this.beingDrawn = false; + + /** + * Timestamp the tile was last touched. + * @member {Number} lastTouchTime + * @memberof OpenSeadragon.Tile# + */ + this.lastTouchTime = 0; + + /** + * Whether this tile is in the right-most column for its level. + * @member {Boolean} isRightMost + * @memberof OpenSeadragon.Tile# + */ + this.isRightMost = false; + + /** + * Whether this tile is in the bottom-most row for its level. + * @member {Boolean} isBottomMost + * @memberof OpenSeadragon.Tile# + */ + this.isBottomMost = false; +}; + +/** @lends OpenSeadragon.Tile.prototype */ +$.Tile.prototype = { + + /** + * Provides a string representation of this tiles level and (x,y) + * components. + * @function + * @returns {String} + */ + toString: function() { + return this.level + "/" + this.x + "_" + this.y; + }, + + // private + _hasTransparencyChannel: function() { + return !!this.context2D || this.url.match('.png'); + }, + + /** + * Renders the tile in an html container. + * @function + * @param {Element} container + */ + drawHTML: function( container ) { + if (!this.cacheImageRecord) { + $.console.warn( + '[Tile.drawHTML] attempting to draw tile %s when it\'s not cached', + this.toString()); + return; + } + + if ( !this.loaded ) { + $.console.warn( + "Attempting to draw tile %s when it's not yet loaded.", + this.toString() + ); + return; + } + + //EXPERIMENTAL - trying to figure out how to scale the container + // content during animation of the container size. + + if ( !this.element ) { + this.element = $.makeNeutralElement( "div" ); + this.imgElement = this.cacheImageRecord.getImage().cloneNode(); + this.imgElement.style.msInterpolationMode = "nearest-neighbor"; + this.imgElement.style.width = "100%"; + this.imgElement.style.height = "100%"; + + this.style = this.element.style; + this.style.position = "absolute"; + } + if ( this.element.parentNode != container ) { + container.appendChild( this.element ); + } + if ( this.imgElement.parentNode != this.element ) { + this.element.appendChild( this.imgElement ); + } + + this.style.top = this.position.y + "px"; + this.style.left = this.position.x + "px"; + this.style.height = this.size.y + "px"; + this.style.width = this.size.x + "px"; + + $.setElementOpacity( this.element, this.opacity ); + }, + + /** + * Renders the tile in a canvas-based context. + * @function + * @param {Canvas} context + * @param {Function} drawingHandler - Method for firing the drawing event. + * drawingHandler({context, tile, rendered}) + * where rendered is the context with the pre-drawn image. + * @param {Number} [scale=1] - Apply a scale to position and size + * @param {OpenSeadragon.Point} [translate] - A translation vector + */ + drawCanvas: function( context, drawingHandler, scale, translate ) { + + var position = this.position.times($.pixelDensityRatio), + size = this.size.times($.pixelDensityRatio), + rendered; + + if (!this.context2D && !this.cacheImageRecord) { + $.console.warn( + '[Tile.drawCanvas] attempting to draw tile %s when it\'s not cached', + this.toString()); + return; + } + + rendered = this.context2D || this.cacheImageRecord.getRenderedContext(); + + if ( !this.loaded || !rendered ){ + $.console.warn( + "Attempting to draw tile %s when it's not yet loaded.", + this.toString() + ); + + return; + } + + context.save(); + + context.globalAlpha = this.opacity; + + if (typeof scale === 'number' && scale !== 1) { + // draw tile at a different scale + position = position.times(scale); + size = size.times(scale); + } + + if (translate instanceof $.Point) { + // shift tile position slightly + position = position.plus(translate); + } + + //if we are supposed to be rendering fully opaque rectangle, + //ie its done fading or fading is turned off, and if we are drawing + //an image with an alpha channel, then the only way + //to avoid seeing the tile underneath is to clear the rectangle + if (context.globalAlpha === 1 && this._hasTransparencyChannel()) { + //clearing only the inside of the rectangle occupied + //by the png prevents edge flikering + context.clearRect( + position.x + 1, + position.y + 1, + size.x - 2, + size.y - 2 + ); + } + + // This gives the application a chance to make image manipulation + // changes as we are rendering the image + drawingHandler({context: context, tile: this, rendered: rendered}); + + context.drawImage( + rendered.canvas, + 0, + 0, + rendered.canvas.width, + rendered.canvas.height, + position.x, + position.y, + size.x, + size.y + ); + + context.restore(); + }, + + /** + * Get the ratio between current and original size. + * @function + * @return {Float} + */ + getScaleForEdgeSmoothing: function() { + var context; + if (this.cacheImageRecord) { + context = this.cacheImageRecord.getRenderedContext(); + } else if (this.context2D) { + context = this.context2D; + } else { + $.console.warn( + '[Tile.drawCanvas] attempting to get tile scale %s when tile\'s not cached', + this.toString()); + return 1; + } + return context.canvas.width / (this.size.x * $.pixelDensityRatio); + }, + + /** + * Get a translation vector that when applied to the tile position produces integer coordinates. + * Needed to avoid swimming and twitching. + * @function + * @param {Number} [scale=1] - Scale to be applied to position. + * @return {OpenSeadragon.Point} + */ + getTranslationForEdgeSmoothing: function(scale, canvasSize, sketchCanvasSize) { + // The translation vector must have positive values, otherwise the image goes a bit off + // the sketch canvas to the top and left and we must use negative coordinates to repaint it + // to the main canvas. In that case, some browsers throw: + // INDEX_SIZE_ERR: DOM Exception 1: Index or size was negative, or greater than the allowed value. + var x = Math.max(1, Math.ceil((sketchCanvasSize.x - canvasSize.x) / 2)); + var y = Math.max(1, Math.ceil((sketchCanvasSize.y - canvasSize.y) / 2)); + return new $.Point(x, y).minus( + this.position + .times($.pixelDensityRatio) + .times(scale || 1) + .apply(function(x) { + return x % 1; + }) + ); + }, + + /** + * Removes tile from its container. + * @function + */ + unload: function() { + if ( this.imgElement && this.imgElement.parentNode ) { + this.imgElement.parentNode.removeChild( this.imgElement ); + } + if ( this.element && this.element.parentNode ) { + this.element.parentNode.removeChild( this.element ); + } + + this.element = null; + this.imgElement = null; + this.loaded = false; + this.loading = false; + } +}; + +}( OpenSeadragon )); + +/* + * OpenSeadragon - Overlay + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function($) { + + /** + * An enumeration of positions that an overlay may be assigned relative to + * the viewport. + * It is identical to OpenSeadragon.Placement but is kept for backward + * compatibility. + * @member OverlayPlacement + * @memberof OpenSeadragon + * @see OpenSeadragon.Placement + * @static + * @readonly + * @type {Object} + * @property {Number} CENTER + * @property {Number} TOP_LEFT + * @property {Number} TOP + * @property {Number} TOP_RIGHT + * @property {Number} RIGHT + * @property {Number} BOTTOM_RIGHT + * @property {Number} BOTTOM + * @property {Number} BOTTOM_LEFT + * @property {Number} LEFT + */ + $.OverlayPlacement = $.Placement; + + /** + * An enumeration of possible ways to handle overlays rotation + * @member OverlayRotationMode + * @memberOf OpenSeadragon + * @static + * @readonly + * @property {Number} NO_ROTATION The overlay ignore the viewport rotation. + * @property {Number} EXACT The overlay use CSS 3 transforms to rotate with + * the viewport. If the overlay contains text, it will get rotated as well. + * @property {Number} BOUNDING_BOX The overlay adjusts for rotation by + * taking the size of the bounding box of the rotated bounds. + * Only valid for overlays with Rect location and scalable in both directions. + */ + $.OverlayRotationMode = $.freezeObject({ + NO_ROTATION: 1, + EXACT: 2, + BOUNDING_BOX: 3 + }); + + /** + * @class Overlay + * @classdesc Provides a way to float an HTML element on top of the viewer element. + * + * @memberof OpenSeadragon + * @param {Object} options + * @param {Element} options.element + * @param {OpenSeadragon.Point|OpenSeadragon.Rect} options.location - The + * location of the overlay on the image. If a {@link OpenSeadragon.Point} + * is specified, the overlay will be located at this location with respect + * to the placement option. If a {@link OpenSeadragon.Rect} is specified, + * the overlay will be placed at this location with the corresponding width + * and height and placement TOP_LEFT. + * @param {OpenSeadragon.Placement} [options.placement=OpenSeadragon.Placement.TOP_LEFT] + * Defines what part of the overlay should be at the specified options.location + * @param {OpenSeadragon.Overlay.OnDrawCallback} [options.onDraw] + * @param {Boolean} [options.checkResize=true] Set to false to avoid to + * check the size of the overlay everytime it is drawn in the directions + * which are not scaled. It will improve performances but will cause a + * misalignment if the overlay size changes. + * @param {Number} [options.width] The width of the overlay in viewport + * coordinates. If specified, the width of the overlay will be adjusted when + * the zoom changes. + * @param {Number} [options.height] The height of the overlay in viewport + * coordinates. If specified, the height of the overlay will be adjusted when + * the zoom changes. + * @param {Boolean} [options.rotationMode=OpenSeadragon.OverlayRotationMode.EXACT] + * How to handle the rotation of the viewport. + */ + $.Overlay = function(element, location, placement) { + + /** + * onDraw callback signature used by {@link OpenSeadragon.Overlay}. + * + * @callback OnDrawCallback + * @memberof OpenSeadragon.Overlay + * @param {OpenSeadragon.Point} position + * @param {OpenSeadragon.Point} size + * @param {Element} element + */ + + var options; + if ($.isPlainObject(element)) { + options = element; + } else { + options = { + element: element, + location: location, + placement: placement + }; + } + + this.element = options.element; + this.style = options.element.style; + this._init(options); + }; + + /** @lends OpenSeadragon.Overlay.prototype */ + $.Overlay.prototype = { + + // private + _init: function(options) { + this.location = options.location; + this.placement = options.placement === undefined ? + $.Placement.TOP_LEFT : options.placement; + this.onDraw = options.onDraw; + this.checkResize = options.checkResize === undefined ? + true : options.checkResize; + + // When this.width is not null, the overlay get scaled horizontally + this.width = options.width === undefined ? null : options.width; + + // When this.height is not null, the overlay get scaled vertically + this.height = options.height === undefined ? null : options.height; + + this.rotationMode = options.rotationMode || $.OverlayRotationMode.EXACT; + + // Having a rect as location is a syntactic sugar + if (this.location instanceof $.Rect) { + this.width = this.location.width; + this.height = this.location.height; + this.location = this.location.getTopLeft(); + this.placement = $.Placement.TOP_LEFT; + } + + // Deprecated properties kept for backward compatibility. + this.scales = this.width !== null && this.height !== null; + this.bounds = new $.Rect( + this.location.x, this.location.y, this.width, this.height); + this.position = this.location; + }, + + /** + * Internal function to adjust the position of an overlay + * depending on it size and placement. + * @function + * @param {OpenSeadragon.Point} position + * @param {OpenSeadragon.Point} size + */ + adjust: function(position, size) { + var properties = $.Placement.properties[this.placement]; + if (!properties) { + return; + } + if (properties.isHorizontallyCentered) { + position.x -= size.x / 2; + } else if (properties.isRight) { + position.x -= size.x; + } + if (properties.isVerticallyCentered) { + position.y -= size.y / 2; + } else if (properties.isBottom) { + position.y -= size.y; + } + }, + + /** + * @function + */ + destroy: function() { + var element = this.element; + var style = this.style; + + if (element.parentNode) { + element.parentNode.removeChild(element); + //this should allow us to preserve overlays when required between + //pages + if (element.prevElementParent) { + style.display = 'none'; + //element.prevElementParent.insertBefore( + // element, + // element.prevNextSibling + //); + document.body.appendChild(element); + } + } + + // clear the onDraw callback + this.onDraw = null; + + style.top = ""; + style.left = ""; + style.position = ""; + + if (this.width !== null) { + style.width = ""; + } + if (this.height !== null) { + style.height = ""; + } + var transformOriginProp = $.getCssPropertyWithVendorPrefix( + 'transformOrigin'); + var transformProp = $.getCssPropertyWithVendorPrefix( + 'transform'); + if (transformOriginProp && transformProp) { + style[transformOriginProp] = ""; + style[transformProp] = ""; + } + }, + + /** + * @function + * @param {Element} container + */ + drawHTML: function(container, viewport) { + var element = this.element; + if (element.parentNode !== container) { + //save the source parent for later if we need it + element.prevElementParent = element.parentNode; + element.prevNextSibling = element.nextSibling; + container.appendChild(element); + + // have to set position before calculating size, fix #1116 + this.style.position = "absolute"; + // this.size is used by overlays which don't get scaled in at + // least one direction when this.checkResize is set to false. + this.size = $.getElementSize(element); + } + + var positionAndSize = this._getOverlayPositionAndSize(viewport); + + var position = positionAndSize.position; + var size = this.size = positionAndSize.size; + var rotate = positionAndSize.rotate; + + // call the onDraw callback if it exists to allow one to overwrite + // the drawing/positioning/sizing of the overlay + if (this.onDraw) { + this.onDraw(position, size, this.element); + } else { + var style = this.style; + style.left = position.x + "px"; + style.top = position.y + "px"; + if (this.width !== null) { + style.width = size.x + "px"; + } + if (this.height !== null) { + style.height = size.y + "px"; + } + var transformOriginProp = $.getCssPropertyWithVendorPrefix( + 'transformOrigin'); + var transformProp = $.getCssPropertyWithVendorPrefix( + 'transform'); + if (transformOriginProp && transformProp) { + if (rotate) { + style[transformOriginProp] = this._getTransformOrigin(); + style[transformProp] = "rotate(" + rotate + "deg)"; + } else { + style[transformOriginProp] = ""; + style[transformProp] = ""; + } + } + + if (style.display !== 'none') { + style.display = 'block'; + } + } + }, + + // private + _getOverlayPositionAndSize: function(viewport) { + var position = viewport.pixelFromPoint(this.location, true); + var size = this._getSizeInPixels(viewport); + this.adjust(position, size); + + var rotate = 0; + if (viewport.degrees && + this.rotationMode !== $.OverlayRotationMode.NO_ROTATION) { + // BOUNDING_BOX is only valid if both directions get scaled. + // Get replaced by EXACT otherwise. + if (this.rotationMode === $.OverlayRotationMode.BOUNDING_BOX && + this.width !== null && this.height !== null) { + var rect = new $.Rect(position.x, position.y, size.x, size.y); + var boundingBox = this._getBoundingBox(rect, viewport.degrees); + position = boundingBox.getTopLeft(); + size = boundingBox.getSize(); + } else { + rotate = viewport.degrees; + } + } + + return { + position: position, + size: size, + rotate: rotate + }; + }, + + // private + _getSizeInPixels: function(viewport) { + var width = this.size.x; + var height = this.size.y; + if (this.width !== null || this.height !== null) { + var scaledSize = viewport.deltaPixelsFromPointsNoRotate( + new $.Point(this.width || 0, this.height || 0), true); + if (this.width !== null) { + width = scaledSize.x; + } + if (this.height !== null) { + height = scaledSize.y; + } + } + if (this.checkResize && + (this.width === null || this.height === null)) { + var eltSize = this.size = $.getElementSize(this.element); + if (this.width === null) { + width = eltSize.x; + } + if (this.height === null) { + height = eltSize.y; + } + } + return new $.Point(width, height); + }, + + // private + _getBoundingBox: function(rect, degrees) { + var refPoint = this._getPlacementPoint(rect); + return rect.rotate(degrees, refPoint).getBoundingBox(); + }, + + // private + _getPlacementPoint: function(rect) { + var result = new $.Point(rect.x, rect.y); + var properties = $.Placement.properties[this.placement]; + if (properties) { + if (properties.isHorizontallyCentered) { + result.x += rect.width / 2; + } else if (properties.isRight) { + result.x += rect.width; + } + if (properties.isVerticallyCentered) { + result.y += rect.height / 2; + } else if (properties.isBottom) { + result.y += rect.height; + } + } + return result; + }, + + // private + _getTransformOrigin: function() { + var result = ""; + var properties = $.Placement.properties[this.placement]; + if (!properties) { + return result; + } + if (properties.isLeft) { + result = "left"; + } else if (properties.isRight) { + result = "right"; + } + if (properties.isTop) { + result += " top"; + } else if (properties.isBottom) { + result += " bottom"; + } + return result; + }, + + /** + * Changes the overlay settings. + * @function + * @param {OpenSeadragon.Point|OpenSeadragon.Rect|Object} location + * If an object is specified, the options are the same than the constructor + * except for the element which can not be changed. + * @param {OpenSeadragon.Placement} placement + */ + update: function(location, placement) { + var options = $.isPlainObject(location) ? location : { + location: location, + placement: placement + }; + this._init({ + location: options.location || this.location, + placement: options.placement !== undefined ? + options.placement : this.placement, + onDraw: options.onDraw || this.onDraw, + checkResize: options.checkResize || this.checkResize, + width: options.width !== undefined ? options.width : this.width, + height: options.height !== undefined ? options.height : this.height, + rotationMode: options.rotationMode || this.rotationMode + }); + }, + + /** + * Returns the current bounds of the overlay in viewport coordinates + * @function + * @param {OpenSeadragon.Viewport} viewport the viewport + * @returns {OpenSeadragon.Rect} overlay bounds + */ + getBounds: function(viewport) { + $.console.assert(viewport, + 'A viewport must now be passed to Overlay.getBounds.'); + var width = this.width; + var height = this.height; + if (width === null || height === null) { + var size = viewport.deltaPointsFromPixelsNoRotate(this.size, true); + if (width === null) { + width = size.x; + } + if (height === null) { + height = size.y; + } + } + var location = this.location.clone(); + this.adjust(location, new $.Point(width, height)); + return this._adjustBoundsForRotation( + viewport, new $.Rect(location.x, location.y, width, height)); + }, + + // private + _adjustBoundsForRotation: function(viewport, bounds) { + if (!viewport || + viewport.degrees === 0 || + this.rotationMode === $.OverlayRotationMode.EXACT) { + return bounds; + } + if (this.rotationMode === $.OverlayRotationMode.BOUNDING_BOX) { + // If overlay not fully scalable, BOUNDING_BOX falls back to EXACT + if (this.width === null || this.height === null) { + return bounds; + } + // It is easier to just compute the position and size and + // convert to viewport coordinates. + var positionAndSize = this._getOverlayPositionAndSize(viewport); + return viewport.viewerElementToViewportRectangle(new $.Rect( + positionAndSize.position.x, + positionAndSize.position.y, + positionAndSize.size.x, + positionAndSize.size.y)); + } + + // NO_ROTATION case + return bounds.rotate(-viewport.degrees, + this._getPlacementPoint(bounds)); + } + }; + +}(OpenSeadragon)); + +/* + * OpenSeadragon - Drawer + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class Drawer + * @memberof OpenSeadragon + * @classdesc Handles rendering of tiles for an {@link OpenSeadragon.Viewer}. + * @param {Object} options - Options for this Drawer. + * @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this Drawer. + * @param {OpenSeadragon.Viewport} options.viewport - Reference to Viewer viewport. + * @param {Element} options.element - Parent element. + * @param {Number} [options.debugGridColor] - See debugGridColor in {@link OpenSeadragon.Options} for details. + */ +$.Drawer = function( options ) { + + $.console.assert( options.viewer, "[Drawer] options.viewer is required" ); + + //backward compatibility for positional args while prefering more + //idiomatic javascript options object as the only argument + var args = arguments; + + if( !$.isPlainObject( options ) ){ + options = { + source: args[ 0 ], // Reference to Viewer tile source. + viewport: args[ 1 ], // Reference to Viewer viewport. + element: args[ 2 ] // Parent element. + }; + } + + $.console.assert( options.viewport, "[Drawer] options.viewport is required" ); + $.console.assert( options.element, "[Drawer] options.element is required" ); + + if ( options.source ) { + $.console.error( "[Drawer] options.source is no longer accepted; use TiledImage instead" ); + } + + this.viewer = options.viewer; + this.viewport = options.viewport; + this.debugGridColor = typeof options.debugGridColor === 'string' ? [options.debugGridColor] : options.debugGridColor || $.DEFAULT_SETTINGS.debugGridColor; + if (options.opacity) { + $.console.error( "[Drawer] options.opacity is no longer accepted; set the opacity on the TiledImage instead" ); + } + + this.useCanvas = $.supportsCanvas && ( this.viewer ? this.viewer.useCanvas : true ); + /** + * The parent element of this Drawer instance, passed in when the Drawer was created. + * The parent of {@link OpenSeadragon.Drawer#canvas}. + * @member {Element} container + * @memberof OpenSeadragon.Drawer# + */ + this.container = $.getElement( options.element ); + /** + * A <canvas> element if the browser supports them, otherwise a <div> element. + * Child element of {@link OpenSeadragon.Drawer#container}. + * @member {Element} canvas + * @memberof OpenSeadragon.Drawer# + */ + this.canvas = $.makeNeutralElement( this.useCanvas ? "canvas" : "div" ); + /** + * 2d drawing context for {@link OpenSeadragon.Drawer#canvas} if it's a <canvas> element, otherwise null. + * @member {Object} context + * @memberof OpenSeadragon.Drawer# + */ + this.context = this.useCanvas ? this.canvas.getContext( "2d" ) : null; + + /** + * Sketch canvas used to temporarily draw tiles which cannot be drawn directly + * to the main canvas due to opacity. Lazily initialized. + */ + this.sketchCanvas = null; + this.sketchContext = null; + + /** + * @member {Element} element + * @memberof OpenSeadragon.Drawer# + * @deprecated Alias for {@link OpenSeadragon.Drawer#container}. + */ + this.element = this.container; + + // We force our container to ltr because our drawing math doesn't work in rtl. + // This issue only affects our canvas renderer, but we do it always for consistency. + // Note that this means overlays you want to be rtl need to be explicitly set to rtl. + this.container.dir = 'ltr'; + + // check canvas available width and height, set canvas width and height such that the canvas backing store is set to the proper pixel density + if (this.useCanvas) { + var viewportSize = this._calculateCanvasSize(); + this.canvas.width = viewportSize.x; + this.canvas.height = viewportSize.y; + } + + this.canvas.style.width = "100%"; + this.canvas.style.height = "100%"; + this.canvas.style.position = "absolute"; + $.setElementOpacity( this.canvas, this.opacity, true ); + + // explicit left-align + this.container.style.textAlign = "left"; + this.container.appendChild( this.canvas ); +}; + +/** @lends OpenSeadragon.Drawer.prototype */ +$.Drawer.prototype = { + // deprecated + addOverlay: function( element, location, placement, onDraw ) { + $.console.error("drawer.addOverlay is deprecated. Use viewer.addOverlay instead."); + this.viewer.addOverlay( element, location, placement, onDraw ); + return this; + }, + + // deprecated + updateOverlay: function( element, location, placement ) { + $.console.error("drawer.updateOverlay is deprecated. Use viewer.updateOverlay instead."); + this.viewer.updateOverlay( element, location, placement ); + return this; + }, + + // deprecated + removeOverlay: function( element ) { + $.console.error("drawer.removeOverlay is deprecated. Use viewer.removeOverlay instead."); + this.viewer.removeOverlay( element ); + return this; + }, + + // deprecated + clearOverlays: function() { + $.console.error("drawer.clearOverlays is deprecated. Use viewer.clearOverlays instead."); + this.viewer.clearOverlays(); + return this; + }, + + /** + * Set the opacity of the drawer. + * @param {Number} opacity + * @return {OpenSeadragon.Drawer} Chainable. + */ + setOpacity: function( opacity ) { + $.console.error("drawer.setOpacity is deprecated. Use tiledImage.setOpacity instead."); + var world = this.viewer.world; + for (var i = 0; i < world.getItemCount(); i++) { + world.getItemAt( i ).setOpacity( opacity ); + } + return this; + }, + + /** + * Get the opacity of the drawer. + * @returns {Number} + */ + getOpacity: function() { + $.console.error("drawer.getOpacity is deprecated. Use tiledImage.getOpacity instead."); + var world = this.viewer.world; + var maxOpacity = 0; + for (var i = 0; i < world.getItemCount(); i++) { + var opacity = world.getItemAt( i ).getOpacity(); + if ( opacity > maxOpacity ) { + maxOpacity = opacity; + } + } + return maxOpacity; + }, + + // deprecated + needsUpdate: function() { + $.console.error( "[Drawer.needsUpdate] this function is deprecated. Use World.needsDraw instead." ); + return this.viewer.world.needsDraw(); + }, + + // deprecated + numTilesLoaded: function() { + $.console.error( "[Drawer.numTilesLoaded] this function is deprecated. Use TileCache.numTilesLoaded instead." ); + return this.viewer.tileCache.numTilesLoaded(); + }, + + // deprecated + reset: function() { + $.console.error( "[Drawer.reset] this function is deprecated. Use World.resetItems instead." ); + this.viewer.world.resetItems(); + return this; + }, + + // deprecated + update: function() { + $.console.error( "[Drawer.update] this function is deprecated. Use Drawer.clear and World.draw instead." ); + this.clear(); + this.viewer.world.draw(); + return this; + }, + + /** + * @return {Boolean} True if rotation is supported. + */ + canRotate: function() { + return this.useCanvas; + }, + + /** + * Destroy the drawer (unload current loaded tiles) + */ + destroy: function() { + //force unloading of current canvas (1x1 will be gc later, trick not necessarily needed) + this.canvas.width = 1; + this.canvas.height = 1; + this.sketchCanvas = null; + this.sketchContext = null; + }, + + /** + * Clears the Drawer so it's ready to draw another frame. + */ + clear: function() { + this.canvas.innerHTML = ""; + if ( this.useCanvas ) { + var viewportSize = this._calculateCanvasSize(); + if( this.canvas.width != viewportSize.x || + this.canvas.height != viewportSize.y ) { + this.canvas.width = viewportSize.x; + this.canvas.height = viewportSize.y; + if ( this.sketchCanvas !== null ) { + var sketchCanvasSize = this._calculateSketchCanvasSize(); + this.sketchCanvas.width = sketchCanvasSize.x; + this.sketchCanvas.height = sketchCanvasSize.y; + } + } + this._clear(); + } + }, + + _clear: function (useSketch, bounds) { + if (!this.useCanvas) { + return; + } + var context = this._getContext(useSketch); + if (bounds) { + context.clearRect(bounds.x, bounds.y, bounds.width, bounds.height); + } else { + var canvas = context.canvas; + context.clearRect(0, 0, canvas.width, canvas.height); + } + }, + + /** + * Scale from OpenSeadragon viewer rectangle to drawer rectangle + * (ignoring rotation) + * @param {OpenSeadragon.Rect} rectangle - The rectangle in viewport coordinate system. + * @return {OpenSeadragon.Rect} Rectangle in drawer coordinate system. + */ + viewportToDrawerRectangle: function(rectangle) { + var topLeft = this.viewport.pixelFromPointNoRotate(rectangle.getTopLeft(), true); + var size = this.viewport.deltaPixelsFromPointsNoRotate(rectangle.getSize(), true); + + return new $.Rect( + topLeft.x * $.pixelDensityRatio, + topLeft.y * $.pixelDensityRatio, + size.x * $.pixelDensityRatio, + size.y * $.pixelDensityRatio + ); + }, + + /** + * Draws the given tile. + * @param {OpenSeadragon.Tile} tile - The tile to draw. + * @param {Function} drawingHandler - Method for firing the drawing event if using canvas. + * drawingHandler({context, tile, rendered}) + * @param {Boolean} useSketch - Whether to use the sketch canvas or not. + * where rendered is the context with the pre-drawn image. + * @param {Float} [scale=1] - Apply a scale to tile position and size. Defaults to 1. + * @param {OpenSeadragon.Point} [translate] A translation vector to offset tile position + */ + drawTile: function(tile, drawingHandler, useSketch, scale, translate) { + $.console.assert(tile, '[Drawer.drawTile] tile is required'); + $.console.assert(drawingHandler, '[Drawer.drawTile] drawingHandler is required'); + + if (this.useCanvas) { + var context = this._getContext(useSketch); + scale = scale || 1; + tile.drawCanvas(context, drawingHandler, scale, translate); + } else { + tile.drawHTML( this.canvas ); + } + }, + + _getContext: function( useSketch ) { + var context = this.context; + if ( useSketch ) { + if (this.sketchCanvas === null) { + this.sketchCanvas = document.createElement( "canvas" ); + var sketchCanvasSize = this._calculateSketchCanvasSize(); + this.sketchCanvas.width = sketchCanvasSize.x; + this.sketchCanvas.height = sketchCanvasSize.y; + this.sketchContext = this.sketchCanvas.getContext( "2d" ); + + // If the viewport is not currently rotated, the sketchCanvas + // will have the same size as the main canvas. However, if + // the viewport get rotated later on, we will need to resize it. + if (this.viewport.getRotation() === 0) { + var self = this; + this.viewer.addHandler('rotate', function resizeSketchCanvas() { + if (self.viewport.getRotation() === 0) { + return; + } + self.viewer.removeHandler('rotate', resizeSketchCanvas); + var sketchCanvasSize = self._calculateSketchCanvasSize(); + self.sketchCanvas.width = sketchCanvasSize.x; + self.sketchCanvas.height = sketchCanvasSize.y; + }); + } + } + context = this.sketchContext; + } + return context; + }, + + // private + saveContext: function( useSketch ) { + if (!this.useCanvas) { + return; + } + + this._getContext( useSketch ).save(); + }, + + // private + restoreContext: function( useSketch ) { + if (!this.useCanvas) { + return; + } + + this._getContext( useSketch ).restore(); + }, + + // private + setClip: function(rect, useSketch) { + if (!this.useCanvas) { + return; + } + + var context = this._getContext( useSketch ); + context.beginPath(); + context.rect(rect.x, rect.y, rect.width, rect.height); + context.clip(); + }, + + // private + drawRectangle: function(rect, fillStyle, useSketch) { + if (!this.useCanvas) { + return; + } + + var context = this._getContext( useSketch ); + context.save(); + context.fillStyle = fillStyle; + context.fillRect(rect.x, rect.y, rect.width, rect.height); + context.restore(); + }, + + /** + * Blends the sketch canvas in the main canvas. + * @param {Object} options The options + * @param {Float} options.opacity The opacity of the blending. + * @param {Float} [options.scale=1] The scale at which tiles were drawn on + * the sketch. Default is 1. + * Use scale to draw at a lower scale and then enlarge onto the main canvas. + * @param {OpenSeadragon.Point} [options.translate] A translation vector + * that was used to draw the tiles + * @param {String} [options.compositeOperation] - How the image is + * composited onto other images; see compositeOperation in + * {@link OpenSeadragon.Options} for possible values. + * @param {OpenSeadragon.Rect} [options.bounds] The part of the sketch + * canvas to blend in the main canvas. If specified, options.scale and + * options.translate get ignored. + */ + blendSketch: function(opacity, scale, translate, compositeOperation) { + var options = opacity; + if (!$.isPlainObject(options)) { + options = { + opacity: opacity, + scale: scale, + translate: translate, + compositeOperation: compositeOperation + }; + } + if (!this.useCanvas || !this.sketchCanvas) { + return; + } + opacity = options.opacity; + compositeOperation = options.compositeOperation; + var bounds = options.bounds; + + this.context.save(); + this.context.globalAlpha = opacity; + if (compositeOperation) { + this.context.globalCompositeOperation = compositeOperation; + } + if (bounds) { + // Internet Explorer, Microsoft Edge, and Safari have problems + // when you call context.drawImage with negative x or y + // or x + width or y + height greater than the canvas width or height respectively. + if (bounds.x < 0) { + bounds.width += bounds.x; + bounds.x = 0; + } + if (bounds.x + bounds.width > this.canvas.width) { + bounds.width = this.canvas.width - bounds.x; + } + if (bounds.y < 0) { + bounds.height += bounds.y; + bounds.y = 0; + } + if (bounds.y + bounds.height > this.canvas.height) { + bounds.height = this.canvas.height - bounds.y; + } + + this.context.drawImage( + this.sketchCanvas, + bounds.x, + bounds.y, + bounds.width, + bounds.height, + bounds.x, + bounds.y, + bounds.width, + bounds.height + ); + } else { + scale = options.scale || 1; + translate = options.translate; + var position = translate instanceof $.Point ? + translate : new $.Point(0, 0); + + var widthExt = 0; + var heightExt = 0; + if (translate) { + var widthDiff = this.sketchCanvas.width - this.canvas.width; + var heightDiff = this.sketchCanvas.height - this.canvas.height; + widthExt = Math.round(widthDiff / 2); + heightExt = Math.round(heightDiff / 2); + } + this.context.drawImage( + this.sketchCanvas, + position.x - widthExt * scale, + position.y - heightExt * scale, + (this.canvas.width + 2 * widthExt) * scale, + (this.canvas.height + 2 * heightExt) * scale, + -widthExt, + -heightExt, + this.canvas.width + 2 * widthExt, + this.canvas.height + 2 * heightExt + ); + } + this.context.restore(); + }, + + // private + drawDebugInfo: function(tile, count, i, tiledImage) { + if ( !this.useCanvas ) { + return; + } + + var colorIndex = this.viewer.world.getIndexOfItem(tiledImage) % this.debugGridColor.length; + var context = this.context; + context.save(); + context.lineWidth = 2 * $.pixelDensityRatio; + context.font = 'small-caps bold ' + (13 * $.pixelDensityRatio) + 'px arial'; + context.strokeStyle = this.debugGridColor[colorIndex]; + context.fillStyle = this.debugGridColor[colorIndex]; + + if ( this.viewport.degrees !== 0 ) { + this._offsetForRotation({degrees: this.viewport.degrees}); + } + if (tiledImage.getRotation(true) % 360 !== 0) { + this._offsetForRotation({ + degrees: tiledImage.getRotation(true), + point: tiledImage.viewport.pixelFromPointNoRotate( + tiledImage._getRotationPoint(true), true) + }); + } + + context.strokeRect( + tile.position.x * $.pixelDensityRatio, + tile.position.y * $.pixelDensityRatio, + tile.size.x * $.pixelDensityRatio, + tile.size.y * $.pixelDensityRatio + ); + + var tileCenterX = (tile.position.x + (tile.size.x / 2)) * $.pixelDensityRatio; + var tileCenterY = (tile.position.y + (tile.size.y / 2)) * $.pixelDensityRatio; + + // Rotate the text the right way around. + context.translate( tileCenterX, tileCenterY ); + context.rotate( Math.PI / 180 * -this.viewport.degrees ); + context.translate( -tileCenterX, -tileCenterY ); + + if( tile.x === 0 && tile.y === 0 ){ + context.fillText( + "Zoom: " + this.viewport.getZoom(), + tile.position.x * $.pixelDensityRatio, + (tile.position.y - 30) * $.pixelDensityRatio + ); + context.fillText( + "Pan: " + this.viewport.getBounds().toString(), + tile.position.x * $.pixelDensityRatio, + (tile.position.y - 20) * $.pixelDensityRatio + ); + } + context.fillText( + "Level: " + tile.level, + (tile.position.x + 10) * $.pixelDensityRatio, + (tile.position.y + 20) * $.pixelDensityRatio + ); + context.fillText( + "Column: " + tile.x, + (tile.position.x + 10) * $.pixelDensityRatio, + (tile.position.y + 30) * $.pixelDensityRatio + ); + context.fillText( + "Row: " + tile.y, + (tile.position.x + 10) * $.pixelDensityRatio, + (tile.position.y + 40) * $.pixelDensityRatio + ); + context.fillText( + "Order: " + i + " of " + count, + (tile.position.x + 10) * $.pixelDensityRatio, + (tile.position.y + 50) * $.pixelDensityRatio + ); + context.fillText( + "Size: " + tile.size.toString(), + (tile.position.x + 10) * $.pixelDensityRatio, + (tile.position.y + 60) * $.pixelDensityRatio + ); + context.fillText( + "Position: " + tile.position.toString(), + (tile.position.x + 10) * $.pixelDensityRatio, + (tile.position.y + 70) * $.pixelDensityRatio + ); + + if ( this.viewport.degrees !== 0 ) { + this._restoreRotationChanges(); + } + if (tiledImage.getRotation(true) % 360 !== 0) { + this._restoreRotationChanges(); + } + context.restore(); + }, + + // private + debugRect: function(rect) { + if ( this.useCanvas ) { + var context = this.context; + context.save(); + context.lineWidth = 2 * $.pixelDensityRatio; + context.strokeStyle = this.debugGridColor[0]; + context.fillStyle = this.debugGridColor[0]; + + context.strokeRect( + rect.x * $.pixelDensityRatio, + rect.y * $.pixelDensityRatio, + rect.width * $.pixelDensityRatio, + rect.height * $.pixelDensityRatio + ); + + context.restore(); + } + }, + + /** + * Get the canvas size + * @param {Boolean} sketch If set to true return the size of the sketch canvas + * @returns {OpenSeadragon.Point} The size of the canvas + */ + getCanvasSize: function(sketch) { + var canvas = this._getContext(sketch).canvas; + return new $.Point(canvas.width, canvas.height); + }, + + getCanvasCenter: function() { + return new $.Point(this.canvas.width / 2, this.canvas.height / 2); + }, + + // private + _offsetForRotation: function(options) { + var point = options.point ? + options.point.times($.pixelDensityRatio) : + this.getCanvasCenter(); + + var context = this._getContext(options.useSketch); + context.save(); + + context.translate(point.x, point.y); + context.rotate(Math.PI / 180 * options.degrees); + context.translate(-point.x, -point.y); + }, + + // private + _restoreRotationChanges: function(useSketch) { + var context = this._getContext(useSketch); + context.restore(); + }, + + // private + _calculateCanvasSize: function() { + var pixelDensityRatio = $.pixelDensityRatio; + var viewportSize = this.viewport.getContainerSize(); + return { + x: viewportSize.x * pixelDensityRatio, + y: viewportSize.y * pixelDensityRatio + }; + }, + + // private + _calculateSketchCanvasSize: function() { + var canvasSize = this._calculateCanvasSize(); + if (this.viewport.getRotation() === 0) { + return canvasSize; + } + // If the viewport is rotated, we need a larger sketch canvas in order + // to support edge smoothing. + var sketchCanvasSize = Math.ceil(Math.sqrt( + canvasSize.x * canvasSize.x + + canvasSize.y * canvasSize.y)); + return { + x: sketchCanvasSize, + y: sketchCanvasSize + }; + } +}; + +}( OpenSeadragon )); + +/* + * OpenSeadragon - Viewport + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + + +/** + * @class Viewport + * @memberof OpenSeadragon + * @classdesc Handles coordinate-related functionality (zoom, pan, rotation, etc.) + * for an {@link OpenSeadragon.Viewer}. + * @param {Object} options - Options for this Viewport. + * @param {Object} [options.margins] - See viewportMargins in {@link OpenSeadragon.Options}. + * @param {Number} [options.springStiffness] - See springStiffness in {@link OpenSeadragon.Options}. + * @param {Number} [options.animationTime] - See animationTime in {@link OpenSeadragon.Options}. + * @param {Number} [options.minZoomImageRatio] - See minZoomImageRatio in {@link OpenSeadragon.Options}. + * @param {Number} [options.maxZoomPixelRatio] - See maxZoomPixelRatio in {@link OpenSeadragon.Options}. + * @param {Number} [options.visibilityRatio] - See visibilityRatio in {@link OpenSeadragon.Options}. + * @param {Boolean} [options.wrapHorizontal] - See wrapHorizontal in {@link OpenSeadragon.Options}. + * @param {Boolean} [options.wrapVertical] - See wrapVertical in {@link OpenSeadragon.Options}. + * @param {Number} [options.defaultZoomLevel] - See defaultZoomLevel in {@link OpenSeadragon.Options}. + * @param {Number} [options.minZoomLevel] - See minZoomLevel in {@link OpenSeadragon.Options}. + * @param {Number} [options.maxZoomLevel] - See maxZoomLevel in {@link OpenSeadragon.Options}. + * @param {Number} [options.degrees] - See degrees in {@link OpenSeadragon.Options}. + * @param {Boolean} [options.homeFillsViewer] - See homeFillsViewer in {@link OpenSeadragon.Options}. + */ +$.Viewport = function( options ) { + + //backward compatibility for positional args while prefering more + //idiomatic javascript options object as the only argument + var args = arguments; + if (args.length && args[0] instanceof $.Point) { + options = { + containerSize: args[0], + contentSize: args[1], + config: args[2] + }; + } + + //options.config and the general config argument are deprecated + //in favor of the more direct specification of optional settings + //being passed directly on the options object + if ( options.config ){ + $.extend( true, options, options.config ); + delete options.config; + } + + this._margins = $.extend({ + left: 0, + top: 0, + right: 0, + bottom: 0 + }, options.margins || {}); + + delete options.margins; + + $.extend( true, this, { + + //required settings + containerSize: null, + contentSize: null, + + //internal state properties + zoomPoint: null, + viewer: null, + + //configurable options + springStiffness: $.DEFAULT_SETTINGS.springStiffness, + animationTime: $.DEFAULT_SETTINGS.animationTime, + minZoomImageRatio: $.DEFAULT_SETTINGS.minZoomImageRatio, + maxZoomPixelRatio: $.DEFAULT_SETTINGS.maxZoomPixelRatio, + visibilityRatio: $.DEFAULT_SETTINGS.visibilityRatio, + wrapHorizontal: $.DEFAULT_SETTINGS.wrapHorizontal, + wrapVertical: $.DEFAULT_SETTINGS.wrapVertical, + defaultZoomLevel: $.DEFAULT_SETTINGS.defaultZoomLevel, + minZoomLevel: $.DEFAULT_SETTINGS.minZoomLevel, + maxZoomLevel: $.DEFAULT_SETTINGS.maxZoomLevel, + degrees: $.DEFAULT_SETTINGS.degrees, + homeFillsViewer: $.DEFAULT_SETTINGS.homeFillsViewer + + }, options ); + + this._updateContainerInnerSize(); + + this.centerSpringX = new $.Spring({ + initial: 0, + springStiffness: this.springStiffness, + animationTime: this.animationTime + }); + this.centerSpringY = new $.Spring({ + initial: 0, + springStiffness: this.springStiffness, + animationTime: this.animationTime + }); + this.zoomSpring = new $.Spring({ + exponential: true, + initial: 1, + springStiffness: this.springStiffness, + animationTime: this.animationTime + }); + + this._oldCenterX = this.centerSpringX.current.value; + this._oldCenterY = this.centerSpringY.current.value; + this._oldZoom = this.zoomSpring.current.value; + + this._setContentBounds(new $.Rect(0, 0, 1, 1), 1); + + this.goHome(true); + this.update(); +}; + +/** @lends OpenSeadragon.Viewport.prototype */ +$.Viewport.prototype = { + /** + * Updates the viewport's home bounds and constraints for the given content size. + * @function + * @param {OpenSeadragon.Point} contentSize - size of the content in content units + * @return {OpenSeadragon.Viewport} Chainable. + * @fires OpenSeadragon.Viewer.event:reset-size + */ + resetContentSize: function(contentSize) { + $.console.assert(contentSize, "[Viewport.resetContentSize] contentSize is required"); + $.console.assert(contentSize instanceof $.Point, "[Viewport.resetContentSize] contentSize must be an OpenSeadragon.Point"); + $.console.assert(contentSize.x > 0, "[Viewport.resetContentSize] contentSize.x must be greater than 0"); + $.console.assert(contentSize.y > 0, "[Viewport.resetContentSize] contentSize.y must be greater than 0"); + + this._setContentBounds(new $.Rect(0, 0, 1, contentSize.y / contentSize.x), contentSize.x); + return this; + }, + + // deprecated + setHomeBounds: function(bounds, contentFactor) { + $.console.error("[Viewport.setHomeBounds] this function is deprecated; The content bounds should not be set manually."); + this._setContentBounds(bounds, contentFactor); + }, + + // Set the viewport's content bounds + // @param {OpenSeadragon.Rect} bounds - the new bounds in viewport coordinates + // without rotation + // @param {Number} contentFactor - how many content units per viewport unit + // @fires OpenSeadragon.Viewer.event:reset-size + // @private + _setContentBounds: function(bounds, contentFactor) { + $.console.assert(bounds, "[Viewport._setContentBounds] bounds is required"); + $.console.assert(bounds instanceof $.Rect, "[Viewport._setContentBounds] bounds must be an OpenSeadragon.Rect"); + $.console.assert(bounds.width > 0, "[Viewport._setContentBounds] bounds.width must be greater than 0"); + $.console.assert(bounds.height > 0, "[Viewport._setContentBounds] bounds.height must be greater than 0"); + + this._contentBoundsNoRotate = bounds.clone(); + this._contentSizeNoRotate = this._contentBoundsNoRotate.getSize().times( + contentFactor); + + this._contentBounds = bounds.rotate(this.degrees).getBoundingBox(); + this._contentSize = this._contentBounds.getSize().times(contentFactor); + this._contentAspectRatio = this._contentSize.x / this._contentSize.y; + + if (this.viewer) { + /** + * Raised when the viewer's content size or home bounds are reset + * (see {@link OpenSeadragon.Viewport#resetContentSize}). + * + * @event reset-size + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.Point} contentSize + * @property {OpenSeadragon.Rect} contentBounds - Content bounds. + * @property {OpenSeadragon.Rect} homeBounds - Content bounds. + * Deprecated use contentBounds instead. + * @property {Number} contentFactor + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.viewer.raiseEvent('reset-size', { + contentSize: this._contentSizeNoRotate.clone(), + contentFactor: contentFactor, + homeBounds: this._contentBoundsNoRotate.clone(), + contentBounds: this._contentBounds.clone() + }); + } + }, + + /** + * Returns the home zoom in "viewport zoom" value. + * @function + * @returns {Number} The home zoom in "viewport zoom". + */ + getHomeZoom: function() { + if (this.defaultZoomLevel) { + return this.defaultZoomLevel; + } + + var aspectFactor = this._contentAspectRatio / this.getAspectRatio(); + var output; + if (this.homeFillsViewer) { // fill the viewer and clip the image + output = aspectFactor >= 1 ? aspectFactor : 1; + } else { + output = aspectFactor >= 1 ? 1 : aspectFactor; + } + + return output / this._contentBounds.width; + }, + + /** + * Returns the home bounds in viewport coordinates. + * @function + * @returns {OpenSeadragon.Rect} The home bounds in vewport coordinates. + */ + getHomeBounds: function() { + return this.getHomeBoundsNoRotate().rotate(-this.getRotation()); + }, + + /** + * Returns the home bounds in viewport coordinates. + * This method ignores the viewport rotation. Use + * {@link OpenSeadragon.Viewport#getHomeBounds} to take it into account. + * @function + * @returns {OpenSeadragon.Rect} The home bounds in vewport coordinates. + */ + getHomeBoundsNoRotate: function() { + var center = this._contentBounds.getCenter(); + var width = 1.0 / this.getHomeZoom(); + var height = width / this.getAspectRatio(); + + return new $.Rect( + center.x - (width / 2.0), + center.y - (height / 2.0), + width, + height + ); + }, + + /** + * @function + * @param {Boolean} immediately + * @fires OpenSeadragon.Viewer.event:home + */ + goHome: function(immediately) { + if (this.viewer) { + /** + * Raised when the "home" operation occurs (see {@link OpenSeadragon.Viewport#goHome}). + * + * @event home + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {Boolean} immediately + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.viewer.raiseEvent('home', { + immediately: immediately + }); + } + return this.fitBounds(this.getHomeBounds(), immediately); + }, + + /** + * @function + */ + getMinZoom: function() { + var homeZoom = this.getHomeZoom(), + zoom = this.minZoomLevel ? + this.minZoomLevel : + this.minZoomImageRatio * homeZoom; + + return zoom; + }, + + /** + * @function + */ + getMaxZoom: function() { + var zoom = this.maxZoomLevel; + if (!zoom) { + zoom = this._contentSize.x * this.maxZoomPixelRatio / this._containerInnerSize.x; + zoom /= this._contentBounds.width; + } + + return Math.max( zoom, this.getHomeZoom() ); + }, + + /** + * @function + */ + getAspectRatio: function() { + return this._containerInnerSize.x / this._containerInnerSize.y; + }, + + /** + * @function + * @returns {OpenSeadragon.Point} The size of the container, in screen coordinates. + */ + getContainerSize: function() { + return new $.Point( + this.containerSize.x, + this.containerSize.y + ); + }, + + /** + * The margins push the "home" region in from the sides by the specified amounts. + * @function + * @returns {Object} Properties (Numbers, in screen coordinates): left, top, right, bottom. + */ + getMargins: function() { + return $.extend({}, this._margins); // Make a copy so we are not returning our original + }, + + /** + * The margins push the "home" region in from the sides by the specified amounts. + * @function + * @param {Object} margins - Properties (Numbers, in screen coordinates): left, top, right, bottom. + */ + setMargins: function(margins) { + $.console.assert($.type(margins) === 'object', '[Viewport.setMargins] margins must be an object'); + + this._margins = $.extend({ + left: 0, + top: 0, + right: 0, + bottom: 0 + }, margins); + + this._updateContainerInnerSize(); + if (this.viewer) { + this.viewer.forceRedraw(); + } + }, + + /** + * Returns the bounds of the visible area in viewport coordinates. + * @function + * @param {Boolean} current - Pass true for the current location; defaults to false (target location). + * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, in viewport coordinates. + */ + getBounds: function(current) { + return this.getBoundsNoRotate(current).rotate(-this.getRotation()); + }, + + /** + * Returns the bounds of the visible area in viewport coordinates. + * This method ignores the viewport rotation. Use + * {@link OpenSeadragon.Viewport#getBounds} to take it into account. + * @function + * @param {Boolean} current - Pass true for the current location; defaults to false (target location). + * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, in viewport coordinates. + */ + getBoundsNoRotate: function(current) { + var center = this.getCenter(current); + var width = 1.0 / this.getZoom(current); + var height = width / this.getAspectRatio(); + + return new $.Rect( + center.x - (width / 2.0), + center.y - (height / 2.0), + width, + height + ); + }, + + /** + * @function + * @param {Boolean} current - Pass true for the current location; defaults to false (target location). + * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, + * including the space taken by margins, in viewport coordinates. + */ + getBoundsWithMargins: function(current) { + return this.getBoundsNoRotateWithMargins(current).rotate( + -this.getRotation(), this.getCenter(current)); + }, + + /** + * @function + * @param {Boolean} current - Pass true for the current location; defaults to false (target location). + * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, + * including the space taken by margins, in viewport coordinates. + */ + getBoundsNoRotateWithMargins: function(current) { + var bounds = this.getBoundsNoRotate(current); + var factor = this._containerInnerSize.x * this.getZoom(current); + bounds.x -= this._margins.left / factor; + bounds.y -= this._margins.top / factor; + bounds.width += (this._margins.left + this._margins.right) / factor; + bounds.height += (this._margins.top + this._margins.bottom) / factor; + return bounds; + }, + + /** + * @function + * @param {Boolean} current - Pass true for the current location; defaults to false (target location). + */ + getCenter: function( current ) { + var centerCurrent = new $.Point( + this.centerSpringX.current.value, + this.centerSpringY.current.value + ), + centerTarget = new $.Point( + this.centerSpringX.target.value, + this.centerSpringY.target.value + ), + oldZoomPixel, + zoom, + width, + height, + bounds, + newZoomPixel, + deltaZoomPixels, + deltaZoomPoints; + + if ( current ) { + return centerCurrent; + } else if ( !this.zoomPoint ) { + return centerTarget; + } + + oldZoomPixel = this.pixelFromPoint(this.zoomPoint, true); + + zoom = this.getZoom(); + width = 1.0 / zoom; + height = width / this.getAspectRatio(); + bounds = new $.Rect( + centerCurrent.x - width / 2.0, + centerCurrent.y - height / 2.0, + width, + height + ); + + newZoomPixel = this._pixelFromPoint(this.zoomPoint, bounds); + deltaZoomPixels = newZoomPixel.minus( oldZoomPixel ); + deltaZoomPoints = deltaZoomPixels.divide( this._containerInnerSize.x * zoom ); + + return centerTarget.plus( deltaZoomPoints ); + }, + + /** + * @function + * @param {Boolean} current - Pass true for the current location; defaults to false (target location). + */ + getZoom: function( current ) { + if ( current ) { + return this.zoomSpring.current.value; + } else { + return this.zoomSpring.target.value; + } + }, + + // private + _applyZoomConstraints: function(zoom) { + return Math.max( + Math.min(zoom, this.getMaxZoom()), + this.getMinZoom()); + }, + + /** + * @function + * @private + * @param {OpenSeadragon.Rect} bounds + * @return {OpenSeadragon.Rect} constrained bounds. + */ + _applyBoundaryConstraints: function(bounds) { + var newBounds = new $.Rect( + bounds.x, + bounds.y, + bounds.width, + bounds.height); + + if (this.wrapHorizontal) { + //do nothing + } else { + var horizontalThreshold = this.visibilityRatio * newBounds.width; + var boundsRight = newBounds.x + newBounds.width; + var contentRight = this._contentBoundsNoRotate.x + this._contentBoundsNoRotate.width; + var leftDx = this._contentBoundsNoRotate.x - boundsRight + horizontalThreshold; + var rightDx = contentRight - newBounds.x - horizontalThreshold; + + if (horizontalThreshold > this._contentBoundsNoRotate.width) { + newBounds.x += (leftDx + rightDx) / 2; + } else if (rightDx < 0) { + newBounds.x += rightDx; + } else if (leftDx > 0) { + newBounds.x += leftDx; + } + } + + if (this.wrapVertical) { + //do nothing + } else { + var verticalThreshold = this.visibilityRatio * newBounds.height; + var boundsBottom = newBounds.y + newBounds.height; + var contentBottom = this._contentBoundsNoRotate.y + this._contentBoundsNoRotate.height; + var topDy = this._contentBoundsNoRotate.y - boundsBottom + verticalThreshold; + var bottomDy = contentBottom - newBounds.y - verticalThreshold; + + if (verticalThreshold > this._contentBoundsNoRotate.height) { + newBounds.y += (topDy + bottomDy) / 2; + } else if (bottomDy < 0) { + newBounds.y += bottomDy; + } else if (topDy > 0) { + newBounds.y += topDy; + } + } + + return newBounds; + }, + + /** + * @function + * @private + * @param {Boolean} [immediately=false] - whether the function that triggered this event was + * called with the "immediately" flag + */ + _raiseConstraintsEvent: function(immediately) { + if (this.viewer) { + /** + * Raised when the viewport constraints are applied (see {@link OpenSeadragon.Viewport#applyConstraints}). + * + * @event constrain + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {Boolean} immediately - whether the function that triggered this event was + * called with the "immediately" flag + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.viewer.raiseEvent( 'constrain', { + immediately: immediately + }); + } + }, + + /** + * Enforces the minZoom, maxZoom and visibilityRatio constraints by + * zooming and panning to the closest acceptable zoom and location. + * @function + * @param {Boolean} [immediately=false] + * @return {OpenSeadragon.Viewport} Chainable. + * @fires OpenSeadragon.Viewer.event:constrain + */ + applyConstraints: function(immediately) { + var actualZoom = this.getZoom(); + var constrainedZoom = this._applyZoomConstraints(actualZoom); + + if (actualZoom !== constrainedZoom) { + this.zoomTo(constrainedZoom, this.zoomPoint, immediately); + } + + var bounds = this.getBoundsNoRotate(); + var constrainedBounds = this._applyBoundaryConstraints(bounds); + this._raiseConstraintsEvent(immediately); + + if (bounds.x !== constrainedBounds.x || + bounds.y !== constrainedBounds.y || + immediately) { + this.fitBounds( + constrainedBounds.rotate(-this.getRotation()), + immediately); + } + return this; + }, + + /** + * Equivalent to {@link OpenSeadragon.Viewport#applyConstraints} + * @function + * @param {Boolean} [immediately=false] + * @return {OpenSeadragon.Viewport} Chainable. + * @fires OpenSeadragon.Viewer.event:constrain + */ + ensureVisible: function(immediately) { + return this.applyConstraints(immediately); + }, + + /** + * @function + * @private + * @param {OpenSeadragon.Rect} bounds + * @param {Object} options (immediately=false, constraints=false) + * @return {OpenSeadragon.Viewport} Chainable. + */ + _fitBounds: function(bounds, options) { + options = options || {}; + var immediately = options.immediately || false; + var constraints = options.constraints || false; + + var aspect = this.getAspectRatio(); + var center = bounds.getCenter(); + + // Compute width and height of bounding box. + var newBounds = new $.Rect( + bounds.x, + bounds.y, + bounds.width, + bounds.height, + bounds.degrees + this.getRotation()) + .getBoundingBox(); + + if (newBounds.getAspectRatio() >= aspect) { + newBounds.height = newBounds.width / aspect; + } else { + newBounds.width = newBounds.height * aspect; + } + + // Compute x and y from width, height and center position + newBounds.x = center.x - newBounds.width / 2; + newBounds.y = center.y - newBounds.height / 2; + var newZoom = 1.0 / newBounds.width; + + if (constraints) { + var newBoundsAspectRatio = newBounds.getAspectRatio(); + var newConstrainedZoom = this._applyZoomConstraints(newZoom); + + if (newZoom !== newConstrainedZoom) { + newZoom = newConstrainedZoom; + newBounds.width = 1.0 / newZoom; + newBounds.x = center.x - newBounds.width / 2; + newBounds.height = newBounds.width / newBoundsAspectRatio; + newBounds.y = center.y - newBounds.height / 2; + } + + newBounds = this._applyBoundaryConstraints(newBounds); + center = newBounds.getCenter(); + this._raiseConstraintsEvent(immediately); + } + + if (immediately) { + this.panTo(center, true); + return this.zoomTo(newZoom, null, true); + } + + this.panTo(this.getCenter(true), true); + this.zoomTo(this.getZoom(true), null, true); + + var oldBounds = this.getBounds(); + var oldZoom = this.getZoom(); + + if (oldZoom === 0 || Math.abs(newZoom / oldZoom - 1) < 0.00000001) { + this.zoomTo(newZoom, true); + return this.panTo(center, immediately); + } + + newBounds = newBounds.rotate(-this.getRotation()); + var referencePoint = newBounds.getTopLeft().times(newZoom) + .minus(oldBounds.getTopLeft().times(oldZoom)) + .divide(newZoom - oldZoom); + + return this.zoomTo(newZoom, referencePoint, immediately); + }, + + /** + * Makes the viewport zoom and pan so that the specified bounds take + * as much space as possible in the viewport. + * Note: this method ignores the constraints (minZoom, maxZoom and + * visibilityRatio). + * Use {@link OpenSeadragon.Viewport#fitBoundsWithConstraints} to enforce + * them. + * @function + * @param {OpenSeadragon.Rect} bounds + * @param {Boolean} [immediately=false] + * @return {OpenSeadragon.Viewport} Chainable. + */ + fitBounds: function(bounds, immediately) { + return this._fitBounds(bounds, { + immediately: immediately, + constraints: false + }); + }, + + /** + * Makes the viewport zoom and pan so that the specified bounds take + * as much space as possible in the viewport while enforcing the constraints + * (minZoom, maxZoom and visibilityRatio). + * Note: because this method enforces the constraints, part of the + * provided bounds may end up outside of the viewport. + * Use {@link OpenSeadragon.Viewport#fitBounds} to ignore them. + * @function + * @param {OpenSeadragon.Rect} bounds + * @param {Boolean} [immediately=false] + * @return {OpenSeadragon.Viewport} Chainable. + */ + fitBoundsWithConstraints: function(bounds, immediately) { + return this._fitBounds(bounds, { + immediately: immediately, + constraints: true + }); + }, + + /** + * Zooms so the image just fills the viewer vertically. + * @param {Boolean} immediately + * @return {OpenSeadragon.Viewport} Chainable. + */ + fitVertically: function(immediately) { + var box = new $.Rect( + this._contentBounds.x + (this._contentBounds.width / 2), + this._contentBounds.y, + 0, + this._contentBounds.height); + return this.fitBounds(box, immediately); + }, + + /** + * Zooms so the image just fills the viewer horizontally. + * @param {Boolean} immediately + * @return {OpenSeadragon.Viewport} Chainable. + */ + fitHorizontally: function(immediately) { + var box = new $.Rect( + this._contentBounds.x, + this._contentBounds.y + (this._contentBounds.height / 2), + this._contentBounds.width, + 0); + return this.fitBounds(box, immediately); + }, + + + /** + * Returns bounds taking constraints into account + * Added to improve constrained panning + * @param {Boolean} current - Pass true for the current location; defaults to false (target location). + * @return {OpenSeadragon.Viewport} Chainable. + */ + getConstrainedBounds: function(current) { + var bounds, + constrainedBounds; + + bounds = this.getBounds(current); + + constrainedBounds = this._applyBoundaryConstraints(bounds); + + return constrainedBounds; + }, + + /** + * @function + * @param {OpenSeadragon.Point} delta + * @param {Boolean} immediately + * @return {OpenSeadragon.Viewport} Chainable. + * @fires OpenSeadragon.Viewer.event:pan + */ + panBy: function( delta, immediately ) { + var center = new $.Point( + this.centerSpringX.target.value, + this.centerSpringY.target.value + ); + return this.panTo( center.plus( delta ), immediately ); + }, + + /** + * @function + * @param {OpenSeadragon.Point} center + * @param {Boolean} immediately + * @return {OpenSeadragon.Viewport} Chainable. + * @fires OpenSeadragon.Viewer.event:pan + */ + panTo: function( center, immediately ) { + if ( immediately ) { + this.centerSpringX.resetTo( center.x ); + this.centerSpringY.resetTo( center.y ); + } else { + this.centerSpringX.springTo( center.x ); + this.centerSpringY.springTo( center.y ); + } + + if( this.viewer ){ + /** + * Raised when the viewport is panned (see {@link OpenSeadragon.Viewport#panBy} and {@link OpenSeadragon.Viewport#panTo}). + * + * @event pan + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.Point} center + * @property {Boolean} immediately + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.viewer.raiseEvent( 'pan', { + center: center, + immediately: immediately + }); + } + + return this; + }, + + /** + * @function + * @return {OpenSeadragon.Viewport} Chainable. + * @fires OpenSeadragon.Viewer.event:zoom + */ + zoomBy: function(factor, refPoint, immediately) { + return this.zoomTo( + this.zoomSpring.target.value * factor, refPoint, immediately); + }, + + /** + * Zooms to the specified zoom level + * @function + * @param {Number} zoom The zoom level to zoom to. + * @param {OpenSeadragon.Point} [refPoint] The point which will stay at + * the same screen location. Defaults to the viewport center. + * @param {Boolean} [immediately=false] + * @return {OpenSeadragon.Viewport} Chainable. + * @fires OpenSeadragon.Viewer.event:zoom + */ + zoomTo: function(zoom, refPoint, immediately) { + var _this = this; + + this.zoomPoint = refPoint instanceof $.Point && + !isNaN(refPoint.x) && + !isNaN(refPoint.y) ? + refPoint : + null; + + if (immediately) { + this._adjustCenterSpringsForZoomPoint(function() { + _this.zoomSpring.resetTo(zoom); + }); + } else { + this.zoomSpring.springTo(zoom); + } + + if (this.viewer) { + /** + * Raised when the viewport zoom level changes (see {@link OpenSeadragon.Viewport#zoomBy} and {@link OpenSeadragon.Viewport#zoomTo}). + * + * @event zoom + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {Number} zoom + * @property {OpenSeadragon.Point} refPoint + * @property {Boolean} immediately + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.viewer.raiseEvent('zoom', { + zoom: zoom, + refPoint: refPoint, + immediately: immediately + }); + } + + return this; + }, + + /** + * Rotates this viewport to the angle specified. + * @function + * @return {OpenSeadragon.Viewport} Chainable. + */ + setRotation: function(degrees) { + if (!this.viewer || !this.viewer.drawer.canRotate()) { + return this; + } + + this.degrees = $.positiveModulo(degrees, 360); + this._setContentBounds( + this.viewer.world.getHomeBounds(), + this.viewer.world.getContentFactor()); + this.viewer.forceRedraw(); + + /** + * Raised when rotation has been changed. + * + * @event rotate + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {Number} degrees - The number of degrees the rotation was set to. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.viewer.raiseEvent('rotate', {"degrees": degrees}); + return this; + }, + + /** + * Gets the current rotation in degrees. + * @function + * @return {Number} The current rotation in degrees. + */ + getRotation: function() { + return this.degrees; + }, + + /** + * @function + * @return {OpenSeadragon.Viewport} Chainable. + * @fires OpenSeadragon.Viewer.event:resize + */ + resize: function( newContainerSize, maintain ) { + var oldBounds = this.getBoundsNoRotate(), + newBounds = oldBounds, + widthDeltaFactor; + + this.containerSize.x = newContainerSize.x; + this.containerSize.y = newContainerSize.y; + + this._updateContainerInnerSize(); + + if ( maintain ) { + // TODO: widthDeltaFactor will always be 1; probably not what's intended + widthDeltaFactor = newContainerSize.x / this.containerSize.x; + newBounds.width = oldBounds.width * widthDeltaFactor; + newBounds.height = newBounds.width / this.getAspectRatio(); + } + + if( this.viewer ){ + /** + * Raised when the viewer is resized (see {@link OpenSeadragon.Viewport#resize}). + * + * @event resize + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.Point} newContainerSize + * @property {Boolean} maintain + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.viewer.raiseEvent( 'resize', { + newContainerSize: newContainerSize, + maintain: maintain + }); + } + + return this.fitBounds( newBounds, true ); + }, + + // private + _updateContainerInnerSize: function() { + this._containerInnerSize = new $.Point( + Math.max(1, this.containerSize.x - (this._margins.left + this._margins.right)), + Math.max(1, this.containerSize.y - (this._margins.top + this._margins.bottom)) + ); + }, + + /** + * Update the zoom and center (X and Y) springs. + * @function + * @returns {Boolean} True if any change has been made, false otherwise. + */ + update: function() { + var _this = this; + this._adjustCenterSpringsForZoomPoint(function() { + _this.zoomSpring.update(); + }); + + this.centerSpringX.update(); + this.centerSpringY.update(); + + var changed = this.centerSpringX.current.value !== this._oldCenterX || + this.centerSpringY.current.value !== this._oldCenterY || + this.zoomSpring.current.value !== this._oldZoom; + + this._oldCenterX = this.centerSpringX.current.value; + this._oldCenterY = this.centerSpringY.current.value; + this._oldZoom = this.zoomSpring.current.value; + + return changed; + }, + + _adjustCenterSpringsForZoomPoint: function(zoomSpringHandler) { + if (this.zoomPoint) { + var oldZoomPixel = this.pixelFromPoint(this.zoomPoint, true); + zoomSpringHandler(); + var newZoomPixel = this.pixelFromPoint(this.zoomPoint, true); + + var deltaZoomPixels = newZoomPixel.minus(oldZoomPixel); + var deltaZoomPoints = this.deltaPointsFromPixels( + deltaZoomPixels, true); + + this.centerSpringX.shiftBy(deltaZoomPoints.x); + this.centerSpringY.shiftBy(deltaZoomPoints.y); + + if (this.zoomSpring.isAtTargetValue()) { + this.zoomPoint = null; + } + } else { + zoomSpringHandler(); + } + }, + + /** + * Convert a delta (translation vector) from viewport coordinates to pixels + * coordinates. This method does not take rotation into account. + * Consider using deltaPixelsFromPoints if you need to account for rotation. + * @param {OpenSeadragon.Point} deltaPoints - The translation vector to convert. + * @param {Boolean} [current=false] - Pass true for the current location; + * defaults to false (target location). + * @returns {OpenSeadragon.Point} + */ + deltaPixelsFromPointsNoRotate: function(deltaPoints, current) { + return deltaPoints.times( + this._containerInnerSize.x * this.getZoom(current) + ); + }, + + /** + * Convert a delta (translation vector) from viewport coordinates to pixels + * coordinates. + * @param {OpenSeadragon.Point} deltaPoints - The translation vector to convert. + * @param {Boolean} [current=false] - Pass true for the current location; + * defaults to false (target location). + * @returns {OpenSeadragon.Point} + */ + deltaPixelsFromPoints: function(deltaPoints, current) { + return this.deltaPixelsFromPointsNoRotate( + deltaPoints.rotate(this.getRotation()), + current); + }, + + /** + * Convert a delta (translation vector) from pixels coordinates to viewport + * coordinates. This method does not take rotation into account. + * Consider using deltaPointsFromPixels if you need to account for rotation. + * @param {OpenSeadragon.Point} deltaPixels - The translation vector to convert. + * @param {Boolean} [current=false] - Pass true for the current location; + * defaults to false (target location). + * @returns {OpenSeadragon.Point} + */ + deltaPointsFromPixelsNoRotate: function(deltaPixels, current) { + return deltaPixels.divide( + this._containerInnerSize.x * this.getZoom(current) + ); + }, + + /** + * Convert a delta (translation vector) from pixels coordinates to viewport + * coordinates. + * @param {OpenSeadragon.Point} deltaPixels - The translation vector to convert. + * @param {Boolean} [current=false] - Pass true for the current location; + * defaults to false (target location). + * @returns {OpenSeadragon.Point} + */ + deltaPointsFromPixels: function(deltaPixels, current) { + return this.deltaPointsFromPixelsNoRotate(deltaPixels, current) + .rotate(-this.getRotation()); + }, + + /** + * Convert viewport coordinates to pixels coordinates. + * This method does not take rotation into account. + * Consider using pixelFromPoint if you need to account for rotation. + * @param {OpenSeadragon.Point} point the viewport coordinates + * @param {Boolean} [current=false] - Pass true for the current location; + * defaults to false (target location). + * @returns {OpenSeadragon.Point} + */ + pixelFromPointNoRotate: function(point, current) { + return this._pixelFromPointNoRotate( + point, this.getBoundsNoRotate(current)); + }, + + /** + * Convert viewport coordinates to pixel coordinates. + * @param {OpenSeadragon.Point} point the viewport coordinates + * @param {Boolean} [current=false] - Pass true for the current location; + * defaults to false (target location). + * @returns {OpenSeadragon.Point} + */ + pixelFromPoint: function(point, current) { + return this._pixelFromPoint(point, this.getBoundsNoRotate(current)); + }, + + // private + _pixelFromPointNoRotate: function(point, bounds) { + return point.minus( + bounds.getTopLeft() + ).times( + this._containerInnerSize.x / bounds.width + ).plus( + new $.Point(this._margins.left, this._margins.top) + ); + }, + + // private + _pixelFromPoint: function(point, bounds) { + return this._pixelFromPointNoRotate( + point.rotate(this.getRotation(), this.getCenter(true)), + bounds); + }, + + /** + * Convert pixel coordinates to viewport coordinates. + * This method does not take rotation into account. + * Consider using pointFromPixel if you need to account for rotation. + * @param {OpenSeadragon.Point} pixel Pixel coordinates + * @param {Boolean} [current=false] - Pass true for the current location; + * defaults to false (target location). + * @returns {OpenSeadragon.Point} + */ + pointFromPixelNoRotate: function(pixel, current) { + var bounds = this.getBoundsNoRotate(current); + return pixel.minus( + new $.Point(this._margins.left, this._margins.top) + ).divide( + this._containerInnerSize.x / bounds.width + ).plus( + bounds.getTopLeft() + ); + }, + + /** + * Convert pixel coordinates to viewport coordinates. + * @param {OpenSeadragon.Point} pixel Pixel coordinates + * @param {Boolean} [current=false] - Pass true for the current location; + * defaults to false (target location). + * @returns {OpenSeadragon.Point} + */ + pointFromPixel: function(pixel, current) { + return this.pointFromPixelNoRotate(pixel, current).rotate( + -this.getRotation(), + this.getCenter(true) + ); + }, + + // private + _viewportToImageDelta: function( viewerX, viewerY ) { + var scale = this._contentBoundsNoRotate.width; + return new $.Point( + viewerX * this._contentSizeNoRotate.x / scale, + viewerY * this._contentSizeNoRotate.x / scale); + }, + + /** + * Translates from OpenSeadragon viewer coordinate system to image coordinate system. + * This method can be called either by passing X,Y coordinates or an + * OpenSeadragon.Point + * Note: not accurate with multi-image; use TiledImage.viewportToImageCoordinates instead. + * @function + * @param {(OpenSeadragon.Point|Number)} viewerX either a point or the X + * coordinate in viewport coordinate system. + * @param {Number} [viewerY] Y coordinate in viewport coordinate system. + * @return {OpenSeadragon.Point} a point representing the coordinates in the image. + */ + viewportToImageCoordinates: function(viewerX, viewerY) { + if (viewerX instanceof $.Point) { + //they passed a point instead of individual components + return this.viewportToImageCoordinates(viewerX.x, viewerX.y); + } + + if (this.viewer) { + var count = this.viewer.world.getItemCount(); + if (count > 1) { + $.console.error('[Viewport.viewportToImageCoordinates] is not accurate ' + + 'with multi-image; use TiledImage.viewportToImageCoordinates instead.'); + } else if (count === 1) { + // It is better to use TiledImage.viewportToImageCoordinates + // because this._contentBoundsNoRotate can not be relied on + // with clipping. + var item = this.viewer.world.getItemAt(0); + return item.viewportToImageCoordinates(viewerX, viewerY, true); + } + } + + return this._viewportToImageDelta( + viewerX - this._contentBoundsNoRotate.x, + viewerY - this._contentBoundsNoRotate.y); + }, + + // private + _imageToViewportDelta: function( imageX, imageY ) { + var scale = this._contentBoundsNoRotate.width; + return new $.Point( + imageX / this._contentSizeNoRotate.x * scale, + imageY / this._contentSizeNoRotate.x * scale); + }, + + /** + * Translates from image coordinate system to OpenSeadragon viewer coordinate system + * This method can be called either by passing X,Y coordinates or an + * OpenSeadragon.Point + * Note: not accurate with multi-image; use TiledImage.imageToViewportCoordinates instead. + * @function + * @param {(OpenSeadragon.Point | Number)} imageX the point or the + * X coordinate in image coordinate system. + * @param {Number} [imageY] Y coordinate in image coordinate system. + * @return {OpenSeadragon.Point} a point representing the coordinates in the viewport. + */ + imageToViewportCoordinates: function(imageX, imageY) { + if (imageX instanceof $.Point) { + //they passed a point instead of individual components + return this.imageToViewportCoordinates(imageX.x, imageX.y); + } + + if (this.viewer) { + var count = this.viewer.world.getItemCount(); + if (count > 1) { + $.console.error('[Viewport.imageToViewportCoordinates] is not accurate ' + + 'with multi-image; use TiledImage.imageToViewportCoordinates instead.'); + } else if (count === 1) { + // It is better to use TiledImage.viewportToImageCoordinates + // because this._contentBoundsNoRotate can not be relied on + // with clipping. + var item = this.viewer.world.getItemAt(0); + return item.imageToViewportCoordinates(imageX, imageY, true); + } + } + + var point = this._imageToViewportDelta(imageX, imageY); + point.x += this._contentBoundsNoRotate.x; + point.y += this._contentBoundsNoRotate.y; + return point; + }, + + /** + * Translates from a rectangle which describes a portion of the image in + * pixel coordinates to OpenSeadragon viewport rectangle coordinates. + * This method can be called either by passing X,Y,width,height or an + * OpenSeadragon.Rect + * Note: not accurate with multi-image; use TiledImage.imageToViewportRectangle instead. + * @function + * @param {(OpenSeadragon.Rect | Number)} imageX the rectangle or the X + * coordinate of the top left corner of the rectangle in image coordinate system. + * @param {Number} [imageY] the Y coordinate of the top left corner of the rectangle + * in image coordinate system. + * @param {Number} [pixelWidth] the width in pixel of the rectangle. + * @param {Number} [pixelHeight] the height in pixel of the rectangle. + * @returns {OpenSeadragon.Rect} This image's bounds in viewport coordinates + */ + imageToViewportRectangle: function(imageX, imageY, pixelWidth, pixelHeight) { + var rect = imageX; + if (!(rect instanceof $.Rect)) { + //they passed individual components instead of a rectangle + rect = new $.Rect(imageX, imageY, pixelWidth, pixelHeight); + } + + if (this.viewer) { + var count = this.viewer.world.getItemCount(); + if (count > 1) { + $.console.error('[Viewport.imageToViewportRectangle] is not accurate ' + + 'with multi-image; use TiledImage.imageToViewportRectangle instead.'); + } else if (count === 1) { + // It is better to use TiledImage.imageToViewportRectangle + // because this._contentBoundsNoRotate can not be relied on + // with clipping. + var item = this.viewer.world.getItemAt(0); + return item.imageToViewportRectangle( + imageX, imageY, pixelWidth, pixelHeight, true); + } + } + + var coordA = this.imageToViewportCoordinates(rect.x, rect.y); + var coordB = this._imageToViewportDelta(rect.width, rect.height); + return new $.Rect( + coordA.x, + coordA.y, + coordB.x, + coordB.y, + rect.degrees + ); + }, + + /** + * Translates from a rectangle which describes a portion of + * the viewport in point coordinates to image rectangle coordinates. + * This method can be called either by passing X,Y,width,height or an + * OpenSeadragon.Rect + * Note: not accurate with multi-image; use TiledImage.viewportToImageRectangle instead. + * @function + * @param {(OpenSeadragon.Rect | Number)} viewerX either a rectangle or + * the X coordinate of the top left corner of the rectangle in viewport + * coordinate system. + * @param {Number} [viewerY] the Y coordinate of the top left corner of the rectangle + * in viewport coordinate system. + * @param {Number} [pointWidth] the width of the rectangle in viewport coordinate system. + * @param {Number} [pointHeight] the height of the rectangle in viewport coordinate system. + */ + viewportToImageRectangle: function(viewerX, viewerY, pointWidth, pointHeight) { + var rect = viewerX; + if (!(rect instanceof $.Rect)) { + //they passed individual components instead of a rectangle + rect = new $.Rect(viewerX, viewerY, pointWidth, pointHeight); + } + + if (this.viewer) { + var count = this.viewer.world.getItemCount(); + if (count > 1) { + $.console.error('[Viewport.viewportToImageRectangle] is not accurate ' + + 'with multi-image; use TiledImage.viewportToImageRectangle instead.'); + } else if (count === 1) { + // It is better to use TiledImage.viewportToImageCoordinates + // because this._contentBoundsNoRotate can not be relied on + // with clipping. + var item = this.viewer.world.getItemAt(0); + return item.viewportToImageRectangle( + viewerX, viewerY, pointWidth, pointHeight, true); + } + } + + var coordA = this.viewportToImageCoordinates(rect.x, rect.y); + var coordB = this._viewportToImageDelta(rect.width, rect.height); + return new $.Rect( + coordA.x, + coordA.y, + coordB.x, + coordB.y, + rect.degrees + ); + }, + + /** + * Convert pixel coordinates relative to the viewer element to image + * coordinates. + * Note: not accurate with multi-image. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + viewerElementToImageCoordinates: function( pixel ) { + var point = this.pointFromPixel( pixel, true ); + return this.viewportToImageCoordinates( point ); + }, + + /** + * Convert pixel coordinates relative to the image to + * viewer element coordinates. + * Note: not accurate with multi-image. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + imageToViewerElementCoordinates: function( pixel ) { + var point = this.imageToViewportCoordinates( pixel ); + return this.pixelFromPoint( point, true ); + }, + + /** + * Convert pixel coordinates relative to the window to image coordinates. + * Note: not accurate with multi-image. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + windowToImageCoordinates: function(pixel) { + $.console.assert(this.viewer, + "[Viewport.windowToImageCoordinates] the viewport must have a viewer."); + var viewerCoordinates = pixel.minus( + $.getElementPosition(this.viewer.element)); + return this.viewerElementToImageCoordinates(viewerCoordinates); + }, + + /** + * Convert image coordinates to pixel coordinates relative to the window. + * Note: not accurate with multi-image. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + imageToWindowCoordinates: function(pixel) { + $.console.assert(this.viewer, + "[Viewport.imageToWindowCoordinates] the viewport must have a viewer."); + var viewerCoordinates = this.imageToViewerElementCoordinates(pixel); + return viewerCoordinates.plus( + $.getElementPosition(this.viewer.element)); + }, + + /** + * Convert pixel coordinates relative to the viewer element to viewport + * coordinates. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + viewerElementToViewportCoordinates: function( pixel ) { + return this.pointFromPixel( pixel, true ); + }, + + /** + * Convert viewport coordinates to pixel coordinates relative to the + * viewer element. + * @param {OpenSeadragon.Point} point + * @returns {OpenSeadragon.Point} + */ + viewportToViewerElementCoordinates: function( point ) { + return this.pixelFromPoint( point, true ); + }, + + /** + * Convert a rectangle in pixel coordinates relative to the viewer element + * to viewport coordinates. + * @param {OpenSeadragon.Rect} rectangle the rectangle to convert + * @returns {OpenSeadragon.Rect} the converted rectangle + */ + viewerElementToViewportRectangle: function(rectangle) { + return $.Rect.fromSummits( + this.pointFromPixel(rectangle.getTopLeft(), true), + this.pointFromPixel(rectangle.getTopRight(), true), + this.pointFromPixel(rectangle.getBottomLeft(), true) + ); + }, + + /** + * Convert a rectangle in viewport coordinates to pixel coordinates relative + * to the viewer element. + * @param {OpenSeadragon.Rect} rectangle the rectangle to convert + * @returns {OpenSeadragon.Rect} the converted rectangle + */ + viewportToViewerElementRectangle: function(rectangle) { + return $.Rect.fromSummits( + this.pixelFromPoint(rectangle.getTopLeft(), true), + this.pixelFromPoint(rectangle.getTopRight(), true), + this.pixelFromPoint(rectangle.getBottomLeft(), true) + ); + }, + + /** + * Convert pixel coordinates relative to the window to viewport coordinates. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + windowToViewportCoordinates: function(pixel) { + $.console.assert(this.viewer, + "[Viewport.windowToViewportCoordinates] the viewport must have a viewer."); + var viewerCoordinates = pixel.minus( + $.getElementPosition(this.viewer.element)); + return this.viewerElementToViewportCoordinates(viewerCoordinates); + }, + + /** + * Convert viewport coordinates to pixel coordinates relative to the window. + * @param {OpenSeadragon.Point} point + * @returns {OpenSeadragon.Point} + */ + viewportToWindowCoordinates: function(point) { + $.console.assert(this.viewer, + "[Viewport.viewportToWindowCoordinates] the viewport must have a viewer."); + var viewerCoordinates = this.viewportToViewerElementCoordinates(point); + return viewerCoordinates.plus( + $.getElementPosition(this.viewer.element)); + }, + + /** + * Convert a viewport zoom to an image zoom. + * Image zoom: ratio of the original image size to displayed image size. + * 1 means original image size, 0.5 half size... + * Viewport zoom: ratio of the displayed image's width to viewport's width. + * 1 means identical width, 2 means image's width is twice the viewport's width... + * Note: not accurate with multi-image. + * @function + * @param {Number} viewportZoom The viewport zoom + * target zoom. + * @returns {Number} imageZoom The image zoom + */ + viewportToImageZoom: function(viewportZoom) { + if (this.viewer) { + var count = this.viewer.world.getItemCount(); + if (count > 1) { + $.console.error('[Viewport.viewportToImageZoom] is not ' + + 'accurate with multi-image.'); + } else if (count === 1) { + // It is better to use TiledImage.viewportToImageZoom + // because this._contentBoundsNoRotate can not be relied on + // with clipping. + var item = this.viewer.world.getItemAt(0); + return item.viewportToImageZoom(viewportZoom); + } + } + + var imageWidth = this._contentSizeNoRotate.x; + var containerWidth = this._containerInnerSize.x; + var scale = this._contentBoundsNoRotate.width; + var viewportToImageZoomRatio = (containerWidth / imageWidth) * scale; + return viewportZoom * viewportToImageZoomRatio; + }, + + /** + * Convert an image zoom to a viewport zoom. + * Image zoom: ratio of the original image size to displayed image size. + * 1 means original image size, 0.5 half size... + * Viewport zoom: ratio of the displayed image's width to viewport's width. + * 1 means identical width, 2 means image's width is twice the viewport's width... + * Note: not accurate with multi-image. + * @function + * @param {Number} imageZoom The image zoom + * target zoom. + * @returns {Number} viewportZoom The viewport zoom + */ + imageToViewportZoom: function(imageZoom) { + if (this.viewer) { + var count = this.viewer.world.getItemCount(); + if (count > 1) { + $.console.error('[Viewport.imageToViewportZoom] is not accurate ' + + 'with multi-image.'); + } else if (count === 1) { + // It is better to use TiledImage.imageToViewportZoom + // because this._contentBoundsNoRotate can not be relied on + // with clipping. + var item = this.viewer.world.getItemAt(0); + return item.imageToViewportZoom(imageZoom); + } + } + + var imageWidth = this._contentSizeNoRotate.x; + var containerWidth = this._containerInnerSize.x; + var scale = this._contentBoundsNoRotate.width; + var viewportToImageZoomRatio = (imageWidth / containerWidth) / scale; + return imageZoom * viewportToImageZoomRatio; + } +}; + +}( OpenSeadragon )); + +/* + * OpenSeadragon - TiledImage + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * You shouldn't have to create a TiledImage directly; use {@link OpenSeadragon.Viewer#open} + * or {@link OpenSeadragon.Viewer#addTiledImage} instead. + * @class TiledImage + * @memberof OpenSeadragon + * @extends OpenSeadragon.EventSource + * @classdesc Handles rendering of tiles for an {@link OpenSeadragon.Viewer}. + * A new instance is created for each TileSource opened. + * @param {Object} options - Configuration for this TiledImage. + * @param {OpenSeadragon.TileSource} options.source - The TileSource that defines this TiledImage. + * @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this TiledImage. + * @param {OpenSeadragon.TileCache} options.tileCache - The TileCache for this TiledImage to use. + * @param {OpenSeadragon.Drawer} options.drawer - The Drawer for this TiledImage to draw onto. + * @param {OpenSeadragon.ImageLoader} options.imageLoader - The ImageLoader for this TiledImage to use. + * @param {Number} [options.x=0] - Left position, in viewport coordinates. + * @param {Number} [options.y=0] - Top position, in viewport coordinates. + * @param {Number} [options.width=1] - Width, in viewport coordinates. + * @param {Number} [options.height] - Height, in viewport coordinates. + * @param {OpenSeadragon.Rect} [options.fitBounds] The bounds in viewport coordinates + * to fit the image into. If specified, x, y, width and height get ignored. + * @param {OpenSeadragon.Placement} [options.fitBoundsPlacement=OpenSeadragon.Placement.CENTER] + * How to anchor the image in the bounds if options.fitBounds is set. + * @param {OpenSeadragon.Rect} [options.clip] - An area, in image pixels, to clip to + * (portions of the image outside of this area will not be visible). Only works on + * browsers that support the HTML5 canvas. + * @param {Number} [options.springStiffness] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.animationTime] - See {@link OpenSeadragon.Options}. + * @param {Number} [options.minZoomImageRatio] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.wrapHorizontal] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.wrapVertical] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.immediateRender] - See {@link OpenSeadragon.Options}. + * @param {Number} [options.blendTime] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.alwaysBlend] - See {@link OpenSeadragon.Options}. + * @param {Number} [options.minPixelRatio] - See {@link OpenSeadragon.Options}. + * @param {Number} [options.smoothTileEdgesMinZoom] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.iOSDevice] - See {@link OpenSeadragon.Options}. + * @param {Number} [options.opacity=1] - Set to draw at proportional opacity. If zero, images will not draw. + * @param {Boolean} [options.preload=false] - Set true to load even when the image is hidden by zero opacity. + * @param {String} [options.compositeOperation] - How the image is composited onto other images; see compositeOperation in {@link OpenSeadragon.Options} for possible values. + * @param {Boolean} [options.debugMode] - See {@link OpenSeadragon.Options}. + * @param {String|CanvasGradient|CanvasPattern|Function} [options.placeholderFillStyle] - See {@link OpenSeadragon.Options}. + * @param {String|Boolean} [options.crossOriginPolicy] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.ajaxWithCredentials] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.loadTilesWithAjax] + * Whether to load tile data using AJAX requests. + * Defaults to the setting in {@link OpenSeadragon.Options}. + * @param {Object} [options.ajaxHeaders={}] + * A set of headers to include when making tile AJAX requests. + */ +$.TiledImage = function( options ) { + var _this = this; + + $.console.assert( options.tileCache, "[TiledImage] options.tileCache is required" ); + $.console.assert( options.drawer, "[TiledImage] options.drawer is required" ); + $.console.assert( options.viewer, "[TiledImage] options.viewer is required" ); + $.console.assert( options.imageLoader, "[TiledImage] options.imageLoader is required" ); + $.console.assert( options.source, "[TiledImage] options.source is required" ); + $.console.assert(!options.clip || options.clip instanceof $.Rect, + "[TiledImage] options.clip must be an OpenSeadragon.Rect if present"); + + $.EventSource.call( this ); + + this._tileCache = options.tileCache; + delete options.tileCache; + + this._drawer = options.drawer; + delete options.drawer; + + this._imageLoader = options.imageLoader; + delete options.imageLoader; + + if (options.clip instanceof $.Rect) { + this._clip = options.clip.clone(); + } + + delete options.clip; + + var x = options.x || 0; + delete options.x; + var y = options.y || 0; + delete options.y; + + // Ratio of zoomable image height to width. + this.normHeight = options.source.dimensions.y / options.source.dimensions.x; + this.contentAspectX = options.source.dimensions.x / options.source.dimensions.y; + + var scale = 1; + if ( options.width ) { + scale = options.width; + delete options.width; + + if ( options.height ) { + $.console.error( "specifying both width and height to a tiledImage is not supported" ); + delete options.height; + } + } else if ( options.height ) { + scale = options.height / this.normHeight; + delete options.height; + } + + var fitBounds = options.fitBounds; + delete options.fitBounds; + var fitBoundsPlacement = options.fitBoundsPlacement || OpenSeadragon.Placement.CENTER; + delete options.fitBoundsPlacement; + + var degrees = options.degrees || 0; + delete options.degrees; + + $.extend( true, this, { + + //internal state properties + viewer: null, + tilesMatrix: {}, // A '3d' dictionary [level][x][y] --> Tile. + coverage: {}, // A '3d' dictionary [level][x][y] --> Boolean; shows what areas have been drawn. + loadingCoverage: {}, // A '3d' dictionary [level][x][y] --> Boolean; shows what areas are loaded or are being loaded/blended. + lastDrawn: [], // An unordered list of Tiles drawn last frame. + lastResetTime: 0, // Last time for which the tiledImage was reset. + _midDraw: false, // Is the tiledImage currently updating the viewport? + _needsDraw: true, // Does the tiledImage need to update the viewport again? + _hasOpaqueTile: false, // Do we have even one fully opaque tile? + _tilesLoading: 0, // The number of pending tile requests. + //configurable settings + springStiffness: $.DEFAULT_SETTINGS.springStiffness, + animationTime: $.DEFAULT_SETTINGS.animationTime, + minZoomImageRatio: $.DEFAULT_SETTINGS.minZoomImageRatio, + wrapHorizontal: $.DEFAULT_SETTINGS.wrapHorizontal, + wrapVertical: $.DEFAULT_SETTINGS.wrapVertical, + immediateRender: $.DEFAULT_SETTINGS.immediateRender, + blendTime: $.DEFAULT_SETTINGS.blendTime, + alwaysBlend: $.DEFAULT_SETTINGS.alwaysBlend, + minPixelRatio: $.DEFAULT_SETTINGS.minPixelRatio, + smoothTileEdgesMinZoom: $.DEFAULT_SETTINGS.smoothTileEdgesMinZoom, + iOSDevice: $.DEFAULT_SETTINGS.iOSDevice, + debugMode: $.DEFAULT_SETTINGS.debugMode, + crossOriginPolicy: $.DEFAULT_SETTINGS.crossOriginPolicy, + ajaxWithCredentials: $.DEFAULT_SETTINGS.ajaxWithCredentials, + placeholderFillStyle: $.DEFAULT_SETTINGS.placeholderFillStyle, + opacity: $.DEFAULT_SETTINGS.opacity, + preload: $.DEFAULT_SETTINGS.preload, + compositeOperation: $.DEFAULT_SETTINGS.compositeOperation + }, options ); + + this._preload = this.preload; + delete this.preload; + + this._fullyLoaded = false; + + this._xSpring = new $.Spring({ + initial: x, + springStiffness: this.springStiffness, + animationTime: this.animationTime + }); + + this._ySpring = new $.Spring({ + initial: y, + springStiffness: this.springStiffness, + animationTime: this.animationTime + }); + + this._scaleSpring = new $.Spring({ + initial: scale, + springStiffness: this.springStiffness, + animationTime: this.animationTime + }); + + this._degreesSpring = new $.Spring({ + initial: degrees, + springStiffness: this.springStiffness, + animationTime: this.animationTime + }); + + this._updateForScale(); + + if (fitBounds) { + this.fitBounds(fitBounds, fitBoundsPlacement, true); + } + + // We need a callback to give image manipulation a chance to happen + this._drawingHandler = function(args) { + /** + * This event is fired just before the tile is drawn giving the application a chance to alter the image. + * + * NOTE: This event is only fired when the drawer is using a <canvas>. + * + * @event tile-drawing + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {OpenSeadragon.Tile} tile - The Tile being drawn. + * @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn. + * @property {OpenSeadragon.Tile} context - The HTML canvas context being drawn into. + * @property {OpenSeadragon.Tile} rendered - The HTML canvas context containing the tile imagery. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + _this.viewer.raiseEvent('tile-drawing', $.extend({ + tiledImage: _this + }, args)); + }; +}; + +$.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.TiledImage.prototype */{ + /** + * @returns {Boolean} Whether the TiledImage needs to be drawn. + */ + needsDraw: function() { + return this._needsDraw; + }, + + /** + * @returns {Boolean} Whether all tiles necessary for this TiledImage to draw at the current view have been loaded. + */ + getFullyLoaded: function() { + return this._fullyLoaded; + }, + + // private + _setFullyLoaded: function(flag) { + if (flag === this._fullyLoaded) { + return; + } + + this._fullyLoaded = flag; + + /** + * Fired when the TiledImage's "fully loaded" flag (whether all tiles necessary for this TiledImage + * to draw at the current view have been loaded) changes. + * + * @event fully-loaded-change + * @memberof OpenSeadragon.TiledImage + * @type {object} + * @property {Boolean} fullyLoaded - The new "fully loaded" value. + * @property {OpenSeadragon.TiledImage} eventSource - A reference to the TiledImage which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('fully-loaded-change', { + fullyLoaded: this._fullyLoaded + }); + }, + + /** + * Clears all tiles and triggers an update on the next call to + * {@link OpenSeadragon.TiledImage#update}. + */ + reset: function() { + this._tileCache.clearTilesFor(this); + this.lastResetTime = $.now(); + this._needsDraw = true; + }, + + /** + * Updates the TiledImage's bounds, animating if needed. + * @returns {Boolean} Whether the TiledImage animated. + */ + update: function() { + var xUpdated = this._xSpring.update(); + var yUpdated = this._ySpring.update(); + var scaleUpdated = this._scaleSpring.update(); + var degreesUpdated = this._degreesSpring.update(); + + if (xUpdated || yUpdated || scaleUpdated || degreesUpdated) { + this._updateForScale(); + this._needsDraw = true; + return true; + } + + return false; + }, + + /** + * Draws the TiledImage to its Drawer. + */ + draw: function() { + if (this.opacity !== 0 || this._preload) { + this._midDraw = true; + this._updateViewport(); + this._midDraw = false; + } + }, + + /** + * Destroy the TiledImage (unload current loaded tiles). + */ + destroy: function() { + this.reset(); + }, + + /** + * Get this TiledImage's bounds in viewport coordinates. + * @param {Boolean} [current=false] - Pass true for the current location; + * false for target location. + * @returns {OpenSeadragon.Rect} This TiledImage's bounds in viewport coordinates. + */ + getBounds: function(current) { + return this.getBoundsNoRotate(current) + .rotate(this.getRotation(current), this._getRotationPoint(current)); + }, + + /** + * Get this TiledImage's bounds in viewport coordinates without taking + * rotation into account. + * @param {Boolean} [current=false] - Pass true for the current location; + * false for target location. + * @returns {OpenSeadragon.Rect} This TiledImage's bounds in viewport coordinates. + */ + getBoundsNoRotate: function(current) { + return current ? + new $.Rect( + this._xSpring.current.value, + this._ySpring.current.value, + this._worldWidthCurrent, + this._worldHeightCurrent) : + new $.Rect( + this._xSpring.target.value, + this._ySpring.target.value, + this._worldWidthTarget, + this._worldHeightTarget); + }, + + // deprecated + getWorldBounds: function() { + $.console.error('[TiledImage.getWorldBounds] is deprecated; use TiledImage.getBounds instead'); + return this.getBounds(); + }, + + /** + * Get the bounds of the displayed part of the tiled image. + * @param {Boolean} [current=false] Pass true for the current location, + * false for the target location. + * @returns {$.Rect} The clipped bounds in viewport coordinates. + */ + getClippedBounds: function(current) { + var bounds = this.getBoundsNoRotate(current); + if (this._clip) { + var worldWidth = current ? + this._worldWidthCurrent : this._worldWidthTarget; + var ratio = worldWidth / this.source.dimensions.x; + var clip = this._clip.times(ratio); + bounds = new $.Rect( + bounds.x + clip.x, + bounds.y + clip.y, + clip.width, + clip.height); + } + return bounds.rotate(this.getRotation(current), this._getRotationPoint(current)); + }, + + /** + * @returns {OpenSeadragon.Point} This TiledImage's content size, in original pixels. + */ + getContentSize: function() { + return new $.Point(this.source.dimensions.x, this.source.dimensions.y); + }, + + // private + _viewportToImageDelta: function( viewerX, viewerY, current ) { + var scale = (current ? this._scaleSpring.current.value : this._scaleSpring.target.value); + return new $.Point(viewerX * (this.source.dimensions.x / scale), + viewerY * ((this.source.dimensions.y * this.contentAspectX) / scale)); + }, + + /** + * Translates from OpenSeadragon viewer coordinate system to image coordinate system. + * This method can be called either by passing X,Y coordinates or an {@link OpenSeadragon.Point}. + * @param {Number|OpenSeadragon.Point} viewerX - The X coordinate or point in viewport coordinate system. + * @param {Number} [viewerY] - The Y coordinate in viewport coordinate system. + * @param {Boolean} [current=false] - Pass true to use the current location; false for target location. + * @return {OpenSeadragon.Point} A point representing the coordinates in the image. + */ + viewportToImageCoordinates: function(viewerX, viewerY, current) { + var point; + if (viewerX instanceof $.Point) { + //they passed a point instead of individual components + current = viewerY; + point = viewerX; + } else { + point = new $.Point(viewerX, viewerY); + } + + point = point.rotate(-this.getRotation(current), this._getRotationPoint(current)); + return current ? + this._viewportToImageDelta( + point.x - this._xSpring.current.value, + point.y - this._ySpring.current.value) : + this._viewportToImageDelta( + point.x - this._xSpring.target.value, + point.y - this._ySpring.target.value); + }, + + // private + _imageToViewportDelta: function( imageX, imageY, current ) { + var scale = (current ? this._scaleSpring.current.value : this._scaleSpring.target.value); + return new $.Point((imageX / this.source.dimensions.x) * scale, + (imageY / this.source.dimensions.y / this.contentAspectX) * scale); + }, + + /** + * Translates from image coordinate system to OpenSeadragon viewer coordinate system + * This method can be called either by passing X,Y coordinates or an {@link OpenSeadragon.Point}. + * @param {Number|OpenSeadragon.Point} imageX - The X coordinate or point in image coordinate system. + * @param {Number} [imageY] - The Y coordinate in image coordinate system. + * @param {Boolean} [current=false] - Pass true to use the current location; false for target location. + * @return {OpenSeadragon.Point} A point representing the coordinates in the viewport. + */ + imageToViewportCoordinates: function(imageX, imageY, current) { + if (imageX instanceof $.Point) { + //they passed a point instead of individual components + current = imageY; + imageY = imageX.y; + imageX = imageX.x; + } + + var point = this._imageToViewportDelta(imageX, imageY); + if (current) { + point.x += this._xSpring.current.value; + point.y += this._ySpring.current.value; + } else { + point.x += this._xSpring.target.value; + point.y += this._ySpring.target.value; + } + + return point.rotate(this.getRotation(current), this._getRotationPoint(current)); + }, + + /** + * Translates from a rectangle which describes a portion of the image in + * pixel coordinates to OpenSeadragon viewport rectangle coordinates. + * This method can be called either by passing X,Y,width,height or an {@link OpenSeadragon.Rect}. + * @param {Number|OpenSeadragon.Rect} imageX - The left coordinate or rectangle in image coordinate system. + * @param {Number} [imageY] - The top coordinate in image coordinate system. + * @param {Number} [pixelWidth] - The width in pixel of the rectangle. + * @param {Number} [pixelHeight] - The height in pixel of the rectangle. + * @param {Boolean} [current=false] - Pass true to use the current location; false for target location. + * @return {OpenSeadragon.Rect} A rect representing the coordinates in the viewport. + */ + imageToViewportRectangle: function(imageX, imageY, pixelWidth, pixelHeight, current) { + var rect = imageX; + if (rect instanceof $.Rect) { + //they passed a rect instead of individual components + current = imageY; + } else { + rect = new $.Rect(imageX, imageY, pixelWidth, pixelHeight); + } + + var coordA = this.imageToViewportCoordinates(rect.getTopLeft(), current); + var coordB = this._imageToViewportDelta(rect.width, rect.height, current); + + return new $.Rect( + coordA.x, + coordA.y, + coordB.x, + coordB.y, + rect.degrees + this.getRotation(current) + ); + }, + + /** + * Translates from a rectangle which describes a portion of + * the viewport in point coordinates to image rectangle coordinates. + * This method can be called either by passing X,Y,width,height or an {@link OpenSeadragon.Rect}. + * @param {Number|OpenSeadragon.Rect} viewerX - The left coordinate or rectangle in viewport coordinate system. + * @param {Number} [viewerY] - The top coordinate in viewport coordinate system. + * @param {Number} [pointWidth] - The width in viewport coordinate system. + * @param {Number} [pointHeight] - The height in viewport coordinate system. + * @param {Boolean} [current=false] - Pass true to use the current location; false for target location. + * @return {OpenSeadragon.Rect} A rect representing the coordinates in the image. + */ + viewportToImageRectangle: function( viewerX, viewerY, pointWidth, pointHeight, current ) { + var rect = viewerX; + if (viewerX instanceof $.Rect) { + //they passed a rect instead of individual components + current = viewerY; + } else { + rect = new $.Rect(viewerX, viewerY, pointWidth, pointHeight); + } + + var coordA = this.viewportToImageCoordinates(rect.getTopLeft(), current); + var coordB = this._viewportToImageDelta(rect.width, rect.height, current); + + return new $.Rect( + coordA.x, + coordA.y, + coordB.x, + coordB.y, + rect.degrees - this.getRotation(current) + ); + }, + + /** + * Convert pixel coordinates relative to the viewer element to image + * coordinates. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + viewerElementToImageCoordinates: function( pixel ) { + var point = this.viewport.pointFromPixel( pixel, true ); + return this.viewportToImageCoordinates( point ); + }, + + /** + * Convert pixel coordinates relative to the image to + * viewer element coordinates. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + imageToViewerElementCoordinates: function( pixel ) { + var point = this.imageToViewportCoordinates( pixel ); + return this.viewport.pixelFromPoint( point, true ); + }, + + /** + * Convert pixel coordinates relative to the window to image coordinates. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + windowToImageCoordinates: function( pixel ) { + var viewerCoordinates = pixel.minus( + OpenSeadragon.getElementPosition( this.viewer.element )); + return this.viewerElementToImageCoordinates( viewerCoordinates ); + }, + + /** + * Convert image coordinates to pixel coordinates relative to the window. + * @param {OpenSeadragon.Point} pixel + * @returns {OpenSeadragon.Point} + */ + imageToWindowCoordinates: function( pixel ) { + var viewerCoordinates = this.imageToViewerElementCoordinates( pixel ); + return viewerCoordinates.plus( + OpenSeadragon.getElementPosition( this.viewer.element )); + }, + + // private + // Convert rectangle in viewport coordinates to this tiled image point + // coordinates (x in [0, 1] and y in [0, aspectRatio]) + _viewportToTiledImageRectangle: function(rect) { + var scale = this._scaleSpring.current.value; + rect = rect.rotate(-this.getRotation(true), this._getRotationPoint(true)); + return new $.Rect( + (rect.x - this._xSpring.current.value) / scale, + (rect.y - this._ySpring.current.value) / scale, + rect.width / scale, + rect.height / scale, + rect.degrees); + }, + + /** + * Convert a viewport zoom to an image zoom. + * Image zoom: ratio of the original image size to displayed image size. + * 1 means original image size, 0.5 half size... + * Viewport zoom: ratio of the displayed image's width to viewport's width. + * 1 means identical width, 2 means image's width is twice the viewport's width... + * @function + * @param {Number} viewportZoom The viewport zoom + * @returns {Number} imageZoom The image zoom + */ + viewportToImageZoom: function( viewportZoom ) { + var ratio = this._scaleSpring.current.value * + this.viewport._containerInnerSize.x / this.source.dimensions.x; + return ratio * viewportZoom; + }, + + /** + * Convert an image zoom to a viewport zoom. + * Image zoom: ratio of the original image size to displayed image size. + * 1 means original image size, 0.5 half size... + * Viewport zoom: ratio of the displayed image's width to viewport's width. + * 1 means identical width, 2 means image's width is twice the viewport's width... + * Note: not accurate with multi-image. + * @function + * @param {Number} imageZoom The image zoom + * @returns {Number} viewportZoom The viewport zoom + */ + imageToViewportZoom: function( imageZoom ) { + var ratio = this._scaleSpring.current.value * + this.viewport._containerInnerSize.x / this.source.dimensions.x; + return imageZoom / ratio; + }, + + /** + * Sets the TiledImage's position in the world. + * @param {OpenSeadragon.Point} position - The new position, in viewport coordinates. + * @param {Boolean} [immediately=false] - Whether to animate to the new position or snap immediately. + * @fires OpenSeadragon.TiledImage.event:bounds-change + */ + setPosition: function(position, immediately) { + var sameTarget = (this._xSpring.target.value === position.x && + this._ySpring.target.value === position.y); + + if (immediately) { + if (sameTarget && this._xSpring.current.value === position.x && + this._ySpring.current.value === position.y) { + return; + } + + this._xSpring.resetTo(position.x); + this._ySpring.resetTo(position.y); + this._needsDraw = true; + } else { + if (sameTarget) { + return; + } + + this._xSpring.springTo(position.x); + this._ySpring.springTo(position.y); + this._needsDraw = true; + } + + if (!sameTarget) { + this._raiseBoundsChange(); + } + }, + + /** + * Sets the TiledImage's width in the world, adjusting the height to match based on aspect ratio. + * @param {Number} width - The new width, in viewport coordinates. + * @param {Boolean} [immediately=false] - Whether to animate to the new size or snap immediately. + * @fires OpenSeadragon.TiledImage.event:bounds-change + */ + setWidth: function(width, immediately) { + this._setScale(width, immediately); + }, + + /** + * Sets the TiledImage's height in the world, adjusting the width to match based on aspect ratio. + * @param {Number} height - The new height, in viewport coordinates. + * @param {Boolean} [immediately=false] - Whether to animate to the new size or snap immediately. + * @fires OpenSeadragon.TiledImage.event:bounds-change + */ + setHeight: function(height, immediately) { + this._setScale(height / this.normHeight, immediately); + }, + + /** + * Positions and scales the TiledImage to fit in the specified bounds. + * Note: this method fires OpenSeadragon.TiledImage.event:bounds-change + * twice + * @param {OpenSeadragon.Rect} bounds The bounds to fit the image into. + * @param {OpenSeadragon.Placement} [anchor=OpenSeadragon.Placement.CENTER] + * How to anchor the image in the bounds. + * @param {Boolean} [immediately=false] Whether to animate to the new size + * or snap immediately. + * @fires OpenSeadragon.TiledImage.event:bounds-change + */ + fitBounds: function(bounds, anchor, immediately) { + anchor = anchor || $.Placement.CENTER; + var anchorProperties = $.Placement.properties[anchor]; + var aspectRatio = this.contentAspectX; + var xOffset = 0; + var yOffset = 0; + var displayedWidthRatio = 1; + var displayedHeightRatio = 1; + if (this._clip) { + aspectRatio = this._clip.getAspectRatio(); + displayedWidthRatio = this._clip.width / this.source.dimensions.x; + displayedHeightRatio = this._clip.height / this.source.dimensions.y; + if (bounds.getAspectRatio() > aspectRatio) { + xOffset = this._clip.x / this._clip.height * bounds.height; + yOffset = this._clip.y / this._clip.height * bounds.height; + } else { + xOffset = this._clip.x / this._clip.width * bounds.width; + yOffset = this._clip.y / this._clip.width * bounds.width; + } + } + + if (bounds.getAspectRatio() > aspectRatio) { + // We will have margins on the X axis + var height = bounds.height / displayedHeightRatio; + var marginLeft = 0; + if (anchorProperties.isHorizontallyCentered) { + marginLeft = (bounds.width - bounds.height * aspectRatio) / 2; + } else if (anchorProperties.isRight) { + marginLeft = bounds.width - bounds.height * aspectRatio; + } + this.setPosition( + new $.Point(bounds.x - xOffset + marginLeft, bounds.y - yOffset), + immediately); + this.setHeight(height, immediately); + } else { + // We will have margins on the Y axis + var width = bounds.width / displayedWidthRatio; + var marginTop = 0; + if (anchorProperties.isVerticallyCentered) { + marginTop = (bounds.height - bounds.width / aspectRatio) / 2; + } else if (anchorProperties.isBottom) { + marginTop = bounds.height - bounds.width / aspectRatio; + } + this.setPosition( + new $.Point(bounds.x - xOffset, bounds.y - yOffset + marginTop), + immediately); + this.setWidth(width, immediately); + } + }, + + /** + * @returns {OpenSeadragon.Rect|null} The TiledImage's current clip rectangle, + * in image pixels, or null if none. + */ + getClip: function() { + if (this._clip) { + return this._clip.clone(); + } + + return null; + }, + + /** + * @param {OpenSeadragon.Rect|null} newClip - An area, in image pixels, to clip to + * (portions of the image outside of this area will not be visible). Only works on + * browsers that support the HTML5 canvas. + * @fires OpenSeadragon.TiledImage.event:clip-change + */ + setClip: function(newClip) { + $.console.assert(!newClip || newClip instanceof $.Rect, + "[TiledImage.setClip] newClip must be an OpenSeadragon.Rect or null"); + + if (newClip instanceof $.Rect) { + this._clip = newClip.clone(); + } else { + this._clip = null; + } + + this._needsDraw = true; + /** + * Raised when the TiledImage's clip is changed. + * @event clip-change + * @memberOf OpenSeadragon.TiledImage + * @type {object} + * @property {OpenSeadragon.TiledImage} eventSource - A reference to the + * TiledImage which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('clip-change'); + }, + + /** + * @returns {Number} The TiledImage's current opacity. + */ + getOpacity: function() { + return this.opacity; + }, + + /** + * @param {Number} opacity Opacity the tiled image should be drawn at. + * @fires OpenSeadragon.TiledImage.event:opacity-change + */ + setOpacity: function(opacity) { + if (opacity === this.opacity) { + return; + } + + this.opacity = opacity; + this._needsDraw = true; + /** + * Raised when the TiledImage's opacity is changed. + * @event opacity-change + * @memberOf OpenSeadragon.TiledImage + * @type {object} + * @property {Number} opacity - The new opacity value. + * @property {OpenSeadragon.TiledImage} eventSource - A reference to the + * TiledImage which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('opacity-change', { + opacity: this.opacity + }); + }, + + /** + * @returns {Boolean} whether the tiledImage can load its tiles even when it has zero opacity. + */ + getPreload: function() { + return this._preload; + }, + + /** + * Set true to load even when hidden. Set false to block loading when hidden. + */ + setPreload: function(preload) { + this._preload = !!preload; + this._needsDraw = true; + }, + + /** + * Get the rotation of this tiled image in degrees. + * @param {Boolean} [current=false] True for current rotation, false for target. + * @returns {Number} the rotation of this tiled image in degrees. + */ + getRotation: function(current) { + return current ? + this._degreesSpring.current.value : + this._degreesSpring.target.value; + }, + + /** + * Set the current rotation of this tiled image in degrees. + * @param {Number} degrees the rotation in degrees. + * @param {Boolean} [immediately=false] Whether to animate to the new angle + * or rotate immediately. + * @fires OpenSeadragon.TiledImage.event:bounds-change + */ + setRotation: function(degrees, immediately) { + if (this._degreesSpring.target.value === degrees && + this._degreesSpring.isAtTargetValue()) { + return; + } + if (immediately) { + this._degreesSpring.resetTo(degrees); + } else { + this._degreesSpring.springTo(degrees); + } + this._needsDraw = true; + this._raiseBoundsChange(); + }, + + /** + * Get the point around which this tiled image is rotated + * @private + * @param {Boolean} current True for current rotation point, false for target. + * @returns {OpenSeadragon.Point} + */ + _getRotationPoint: function(current) { + return this.getBoundsNoRotate(current).getCenter(); + }, + + /** + * @returns {String} The TiledImage's current compositeOperation. + */ + getCompositeOperation: function() { + return this.compositeOperation; + }, + + /** + * @param {String} compositeOperation the tiled image should be drawn with this globalCompositeOperation. + * @fires OpenSeadragon.TiledImage.event:composite-operation-change + */ + setCompositeOperation: function(compositeOperation) { + if (compositeOperation === this.compositeOperation) { + return; + } + + this.compositeOperation = compositeOperation; + this._needsDraw = true; + /** + * Raised when the TiledImage's opacity is changed. + * @event composite-operation-change + * @memberOf OpenSeadragon.TiledImage + * @type {object} + * @property {String} compositeOperation - The new compositeOperation value. + * @property {OpenSeadragon.TiledImage} eventSource - A reference to the + * TiledImage which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('composite-operation-change', { + compositeOperation: this.compositeOperation + }); + }, + + // private + _setScale: function(scale, immediately) { + var sameTarget = (this._scaleSpring.target.value === scale); + if (immediately) { + if (sameTarget && this._scaleSpring.current.value === scale) { + return; + } + + this._scaleSpring.resetTo(scale); + this._updateForScale(); + this._needsDraw = true; + } else { + if (sameTarget) { + return; + } + + this._scaleSpring.springTo(scale); + this._updateForScale(); + this._needsDraw = true; + } + + if (!sameTarget) { + this._raiseBoundsChange(); + } + }, + + // private + _updateForScale: function() { + this._worldWidthTarget = this._scaleSpring.target.value; + this._worldHeightTarget = this.normHeight * this._scaleSpring.target.value; + this._worldWidthCurrent = this._scaleSpring.current.value; + this._worldHeightCurrent = this.normHeight * this._scaleSpring.current.value; + }, + + // private + _raiseBoundsChange: function() { + /** + * Raised when the TiledImage's bounds are changed. + * Note that this event is triggered only when the animation target is changed; + * not for every frame of animation. + * @event bounds-change + * @memberOf OpenSeadragon.TiledImage + * @type {object} + * @property {OpenSeadragon.TiledImage} eventSource - A reference to the + * TiledImage which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('bounds-change'); + }, + + // private + _isBottomItem: function() { + return this.viewer.world.getItemAt(0) === this; + }, + + // private + _getLevelsInterval: function() { + var lowestLevel = Math.max( + this.source.minLevel, + Math.floor(Math.log(this.minZoomImageRatio) / Math.log(2)) + ); + var currentZeroRatio = this.viewport.deltaPixelsFromPointsNoRotate( + this.source.getPixelRatio(0), true).x * + this._scaleSpring.current.value; + var highestLevel = Math.min( + Math.abs(this.source.maxLevel), + Math.abs(Math.floor( + Math.log(currentZeroRatio / this.minPixelRatio) / Math.log(2) + )) + ); + + // Calculations for the interval of levels to draw + // can return invalid intervals; fix that here if necessary + lowestLevel = Math.min(lowestLevel, highestLevel); + return { + lowestLevel: lowestLevel, + highestLevel: highestLevel + }; + }, + + /** + * @private + * @inner + * Pretty much every other line in this needs to be documented so it's clear + * how each piece of this routine contributes to the drawing process. That's + * why there are so many TODO's inside this function. + */ + _updateViewport: function() { + this._needsDraw = false; + this._tilesLoading = 0; + this.loadingCoverage = {}; + + // Reset tile's internal drawn state + while (this.lastDrawn.length > 0) { + var tile = this.lastDrawn.pop(); + tile.beingDrawn = false; + } + + var viewport = this.viewport; + var drawArea = this._viewportToTiledImageRectangle( + viewport.getBoundsWithMargins(true)); + + if (!this.wrapHorizontal && !this.wrapVertical) { + var tiledImageBounds = this._viewportToTiledImageRectangle( + this.getClippedBounds(true)); + drawArea = drawArea.intersection(tiledImageBounds); + if (drawArea === null) { + return; + } + } + + var levelsInterval = this._getLevelsInterval(); + var lowestLevel = levelsInterval.lowestLevel; + var highestLevel = levelsInterval.highestLevel; + var bestTile = null; + var haveDrawn = false; + var currentTime = $.now(); + + // Update any level that will be drawn + for (var level = highestLevel; level >= lowestLevel; level--) { + var drawLevel = false; + + //Avoid calculations for draw if we have already drawn this + var currentRenderPixelRatio = viewport.deltaPixelsFromPointsNoRotate( + this.source.getPixelRatio(level), + true + ).x * this._scaleSpring.current.value; + + if (level === lowestLevel || + (!haveDrawn && currentRenderPixelRatio >= this.minPixelRatio)) { + drawLevel = true; + haveDrawn = true; + } else if (!haveDrawn) { + continue; + } + + //Perform calculations for draw if we haven't drawn this + var targetRenderPixelRatio = viewport.deltaPixelsFromPointsNoRotate( + this.source.getPixelRatio(level), + false + ).x * this._scaleSpring.current.value; + + var targetZeroRatio = viewport.deltaPixelsFromPointsNoRotate( + this.source.getPixelRatio( + Math.max( + this.source.getClosestLevel(), + 0 + ) + ), + false + ).x * this._scaleSpring.current.value; + + var optimalRatio = this.immediateRender ? 1 : targetZeroRatio; + var levelOpacity = Math.min(1, (currentRenderPixelRatio - 0.5) / 0.5); + var levelVisibility = optimalRatio / Math.abs( + optimalRatio - targetRenderPixelRatio + ); + + // Update the level and keep track of 'best' tile to load + bestTile = updateLevel( + this, + haveDrawn, + drawLevel, + level, + levelOpacity, + levelVisibility, + drawArea, + currentTime, + bestTile + ); + + // Stop the loop if lower-res tiles would all be covered by + // already drawn tiles + if (providesCoverage(this.coverage, level)) { + break; + } + } + + // Perform the actual drawing + drawTiles(this, this.lastDrawn); + + // Load the new 'best' tile + if (bestTile && !bestTile.context2D) { + loadTile(this, bestTile, currentTime); + this._needsDraw = true; + this._setFullyLoaded(false); + } else { + this._setFullyLoaded(this._tilesLoading === 0); + } + }, + + // private + _getCornerTiles: function(level, topLeftBound, bottomRightBound) { + var leftX; + var rightX; + if (this.wrapHorizontal) { + leftX = $.positiveModulo(topLeftBound.x, 1); + rightX = $.positiveModulo(bottomRightBound.x, 1); + } else { + leftX = Math.max(0, topLeftBound.x); + rightX = Math.min(1, bottomRightBound.x); + } + var topY; + var bottomY; + var aspectRatio = 1 / this.source.aspectRatio; + if (this.wrapVertical) { + topY = $.positiveModulo(topLeftBound.y, aspectRatio); + bottomY = $.positiveModulo(bottomRightBound.y, aspectRatio); + } else { + topY = Math.max(0, topLeftBound.y); + bottomY = Math.min(aspectRatio, bottomRightBound.y); + } + + var topLeftTile = this.source.getTileAtPoint(level, new $.Point(leftX, topY)); + var bottomRightTile = this.source.getTileAtPoint(level, new $.Point(rightX, bottomY)); + var numTiles = this.source.getNumTiles(level); + + if (this.wrapHorizontal) { + topLeftTile.x += numTiles.x * Math.floor(topLeftBound.x); + bottomRightTile.x += numTiles.x * Math.floor(bottomRightBound.x); + } + if (this.wrapVertical) { + topLeftTile.y += numTiles.y * Math.floor(topLeftBound.y / aspectRatio); + bottomRightTile.y += numTiles.y * Math.floor(bottomRightBound.y / aspectRatio); + } + + return { + topLeft: topLeftTile, + bottomRight: bottomRightTile, + }; + } +}); + +/** + * @private + * @inner + * Updates all tiles at a given resolution level. + * @param {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn. + * @param {Boolean} haveDrawn + * @param {Boolean} drawLevel + * @param {Number} level + * @param {Number} levelOpacity + * @param {Number} levelVisibility + * @param {OpenSeadragon.Point} viewportTL - The index of the most top-left visible tile. + * @param {OpenSeadragon.Point} viewportBR - The index of the most bottom-right visible tile. + * @param {Number} currentTime + * @param {OpenSeadragon.Tile} best - The current "best" tile to draw. + */ +function updateLevel(tiledImage, haveDrawn, drawLevel, level, levelOpacity, + levelVisibility, drawArea, currentTime, best) { + + var topLeftBound = drawArea.getBoundingBox().getTopLeft(); + var bottomRightBound = drawArea.getBoundingBox().getBottomRight(); + + if (tiledImage.viewer) { + /** + * - Needs documentation - + * + * @event update-level + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn. + * @property {Object} havedrawn + * @property {Object} level + * @property {Object} opacity + * @property {Object} visibility + * @property {OpenSeadragon.Rect} drawArea + * @property {Object} topleft deprecated, use drawArea instead + * @property {Object} bottomright deprecated, use drawArea instead + * @property {Object} currenttime + * @property {Object} best + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + tiledImage.viewer.raiseEvent('update-level', { + tiledImage: tiledImage, + havedrawn: haveDrawn, + level: level, + opacity: levelOpacity, + visibility: levelVisibility, + drawArea: drawArea, + topleft: topLeftBound, + bottomright: bottomRightBound, + currenttime: currentTime, + best: best + }); + } + + resetCoverage(tiledImage.coverage, level); + resetCoverage(tiledImage.loadingCoverage, level); + + //OK, a new drawing so do your calculations + var cornerTiles = tiledImage._getCornerTiles(level, topLeftBound, bottomRightBound); + var topLeftTile = cornerTiles.topLeft; + var bottomRightTile = cornerTiles.bottomRight; + var numberOfTiles = tiledImage.source.getNumTiles(level); + + var viewportCenter = tiledImage.viewport.pixelFromPoint( + tiledImage.viewport.getCenter()); + for (var x = topLeftTile.x; x <= bottomRightTile.x; x++) { + for (var y = topLeftTile.y; y <= bottomRightTile.y; y++) { + + // Optimisation disabled with wrapping because getTileBounds does not + // work correctly with x and y outside of the number of tiles + if (!tiledImage.wrapHorizontal && !tiledImage.wrapVertical) { + var tileBounds = tiledImage.source.getTileBounds(level, x, y); + if (drawArea.intersection(tileBounds) === null) { + // This tile is outside of the viewport, no need to draw it + continue; + } + } + + best = updateTile( + tiledImage, + drawLevel, + haveDrawn, + x, y, + level, + levelOpacity, + levelVisibility, + viewportCenter, + numberOfTiles, + currentTime, + best + ); + + } + } + + return best; +} + +/** + * @private + * @inner + * Update a single tile at a particular resolution level. + * @param {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn. + * @param {Boolean} haveDrawn + * @param {Boolean} drawLevel + * @param {Number} x + * @param {Number} y + * @param {Number} level + * @param {Number} levelOpacity + * @param {Number} levelVisibility + * @param {OpenSeadragon.Point} viewportCenter + * @param {Number} numberOfTiles + * @param {Number} currentTime + * @param {OpenSeadragon.Tile} best - The current "best" tile to draw. + */ +function updateTile( tiledImage, haveDrawn, drawLevel, x, y, level, levelOpacity, levelVisibility, viewportCenter, numberOfTiles, currentTime, best){ + + var tile = getTile( + x, y, + level, + tiledImage, + tiledImage.source, + tiledImage.tilesMatrix, + currentTime, + numberOfTiles, + tiledImage._worldWidthCurrent, + tiledImage._worldHeightCurrent + ), + drawTile = drawLevel; + + if( tiledImage.viewer ){ + /** + * - Needs documentation - + * + * @event update-tile + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn. + * @property {OpenSeadragon.Tile} tile + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + tiledImage.viewer.raiseEvent( 'update-tile', { + tiledImage: tiledImage, + tile: tile + }); + } + + setCoverage( tiledImage.coverage, level, x, y, false ); + + var loadingCoverage = tile.loaded || tile.loading || isCovered(tiledImage.loadingCoverage, level, x, y); + setCoverage(tiledImage.loadingCoverage, level, x, y, loadingCoverage); + + if ( !tile.exists ) { + return best; + } + + if ( haveDrawn && !drawTile ) { + if ( isCovered( tiledImage.coverage, level, x, y ) ) { + setCoverage( tiledImage.coverage, level, x, y, true ); + } else { + drawTile = true; + } + } + + if ( !drawTile ) { + return best; + } + + positionTile( + tile, + tiledImage.source.tileOverlap, + tiledImage.viewport, + viewportCenter, + levelVisibility, + tiledImage + ); + + if (!tile.loaded) { + if (tile.context2D) { + setTileLoaded(tiledImage, tile); + } else { + var imageRecord = tiledImage._tileCache.getImageRecord(tile.cacheKey); + if (imageRecord) { + var image = imageRecord.getImage(); + setTileLoaded(tiledImage, tile, image); + } + } + } + + if ( tile.loaded ) { + var needsDraw = blendTile( + tiledImage, + tile, + x, y, + level, + levelOpacity, + currentTime + ); + + if ( needsDraw ) { + tiledImage._needsDraw = true; + } + } else if ( tile.loading ) { + // the tile is already in the download queue + tiledImage._tilesLoading++; + } else if (!loadingCoverage) { + best = compareTiles( best, tile ); + } + + return best; +} + +/** + * @private + * @inner + * Obtains a tile at the given location. + * @param {Number} x + * @param {Number} y + * @param {Number} level + * @param {OpenSeadragon.TiledImage} tiledImage + * @param {OpenSeadragon.TileSource} tileSource + * @param {Object} tilesMatrix - A '3d' dictionary [level][x][y] --> Tile. + * @param {Number} time + * @param {Number} numTiles + * @param {Number} worldWidth + * @param {Number} worldHeight + * @returns {OpenSeadragon.Tile} + */ +function getTile( + x, y, + level, + tiledImage, + tileSource, + tilesMatrix, + time, + numTiles, + worldWidth, + worldHeight +) { + var xMod, + yMod, + bounds, + exists, + url, + ajaxHeaders, + context2D, + tile; + + if ( !tilesMatrix[ level ] ) { + tilesMatrix[ level ] = {}; + } + if ( !tilesMatrix[ level ][ x ] ) { + tilesMatrix[ level ][ x ] = {}; + } + + if ( !tilesMatrix[ level ][ x ][ y ] ) { + xMod = ( numTiles.x + ( x % numTiles.x ) ) % numTiles.x; + yMod = ( numTiles.y + ( y % numTiles.y ) ) % numTiles.y; + bounds = tileSource.getTileBounds( level, xMod, yMod ); + exists = tileSource.tileExists( level, xMod, yMod ); + url = tileSource.getTileUrl( level, xMod, yMod ); + + // Headers are only applicable if loadTilesWithAjax is set + if (tiledImage.loadTilesWithAjax) { + ajaxHeaders = tileSource.getTileAjaxHeaders( level, xMod, yMod ); + // Combine tile AJAX headers with tiled image AJAX headers (if applicable) + if ($.isPlainObject(tiledImage.ajaxHeaders)) { + ajaxHeaders = $.extend({}, tiledImage.ajaxHeaders, ajaxHeaders); + } + } else { + ajaxHeaders = null; + } + + context2D = tileSource.getContext2D ? + tileSource.getContext2D(level, xMod, yMod) : undefined; + + bounds.x += ( x - xMod ) / numTiles.x; + bounds.y += (worldHeight / worldWidth) * (( y - yMod ) / numTiles.y); + + tile = new $.Tile( + level, + x, + y, + bounds, + exists, + url, + context2D, + tiledImage.loadTilesWithAjax, + ajaxHeaders + ); + + if (xMod === numTiles.x - 1) { + tile.isRightMost = true; + } + + if (yMod === numTiles.y - 1) { + tile.isBottomMost = true; + } + + tilesMatrix[ level ][ x ][ y ] = tile; + } + + tile = tilesMatrix[ level ][ x ][ y ]; + tile.lastTouchTime = time; + + return tile; +} + +/** + * @private + * @inner + * Dispatch a job to the ImageLoader to load the Image for a Tile. + * @param {OpenSeadragon.TiledImage} tiledImage + * @param {OpenSeadragon.Tile} tile + * @param {Number} time + */ +function loadTile( tiledImage, tile, time ) { + tile.loading = true; + tiledImage._imageLoader.addJob({ + src: tile.url, + loadWithAjax: tile.loadWithAjax, + ajaxHeaders: tile.ajaxHeaders, + crossOriginPolicy: tiledImage.crossOriginPolicy, + ajaxWithCredentials: tiledImage.ajaxWithCredentials, + callback: function( image, errorMsg, tileRequest ){ + onTileLoad( tiledImage, tile, time, image, errorMsg, tileRequest ); + }, + abort: function() { + tile.loading = false; + } + }); +} + +/** + * @private + * @inner + * Callback fired when a Tile's Image finished downloading. + * @param {OpenSeadragon.TiledImage} tiledImage + * @param {OpenSeadragon.Tile} tile + * @param {Number} time + * @param {Image} image + * @param {String} errorMsg + * @param {XMLHttpRequest} tileRequest + */ +function onTileLoad( tiledImage, tile, time, image, errorMsg, tileRequest ) { + if ( !image ) { + $.console.log( "Tile %s failed to load: %s - error: %s", tile, tile.url, errorMsg ); + /** + * Triggered when a tile fails to load. + * + * @event tile-load-failed + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Tile} tile - The tile that failed to load. + * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image the tile belongs to. + * @property {number} time - The time in milliseconds when the tile load began. + * @property {string} message - The error message. + * @property {XMLHttpRequest} tileRequest - The XMLHttpRequest used to load the tile if available. + */ + tiledImage.viewer.raiseEvent("tile-load-failed", { + tile: tile, + tiledImage: tiledImage, + time: time, + message: errorMsg, + tileRequest: tileRequest + }); + tile.loading = false; + tile.exists = false; + return; + } + + if ( time < tiledImage.lastResetTime ) { + $.console.log( "Ignoring tile %s loaded before reset: %s", tile, tile.url ); + tile.loading = false; + return; + } + + var finish = function() { + var cutoff = tiledImage.source.getClosestLevel(); + setTileLoaded(tiledImage, tile, image, cutoff, tileRequest); + }; + + // Check if we're mid-update; this can happen on IE8 because image load events for + // cached images happen immediately there + if ( !tiledImage._midDraw ) { + finish(); + } else { + // Wait until after the update, in case caching unloads any tiles + window.setTimeout( finish, 1); + } +} + +/** + * @private + * @inner + * @param {OpenSeadragon.TiledImage} tiledImage + * @param {OpenSeadragon.Tile} tile + * @param {Image} image + * @param {Number} cutoff + */ +function setTileLoaded(tiledImage, tile, image, cutoff, tileRequest) { + var increment = 0; + + function getCompletionCallback() { + increment++; + return completionCallback; + } + + function completionCallback() { + increment--; + if (increment === 0) { + tile.loading = false; + tile.loaded = true; + if (!tile.context2D) { + tiledImage._tileCache.cacheTile({ + image: image, + tile: tile, + cutoff: cutoff, + tiledImage: tiledImage + }); + } + tiledImage._needsDraw = true; + } + } + + /** + * Triggered when a tile has just been loaded in memory. That means that the + * image has been downloaded and can be modified before being drawn to the canvas. + * + * @event tile-loaded + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {Image} image - The image of the tile. + * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image of the loaded tile. + * @property {OpenSeadragon.Tile} tile - The tile which has been loaded. + * @property {XMLHttpRequest} tiledImage - The AJAX request that loaded this tile (if applicable). + * @property {function} getCompletionCallback - A function giving a callback to call + * when the asynchronous processing of the image is done. The image will be + * marked as entirely loaded when the callback has been called once for each + * call to getCompletionCallback. + */ + tiledImage.viewer.raiseEvent("tile-loaded", { + tile: tile, + tiledImage: tiledImage, + tileRequest: tileRequest, + image: image, + getCompletionCallback: getCompletionCallback + }); + // In case the completion callback is never called, we at least force it once. + getCompletionCallback()(); +} + +/** + * @private + * @inner + * @param {OpenSeadragon.Tile} tile + * @param {Boolean} overlap + * @param {OpenSeadragon.Viewport} viewport + * @param {OpenSeadragon.Point} viewportCenter + * @param {Number} levelVisibility + * @param {OpenSeadragon.TiledImage} tiledImage + */ +function positionTile( tile, overlap, viewport, viewportCenter, levelVisibility, tiledImage ){ + var boundsTL = tile.bounds.getTopLeft(); + + boundsTL.x *= tiledImage._scaleSpring.current.value; + boundsTL.y *= tiledImage._scaleSpring.current.value; + boundsTL.x += tiledImage._xSpring.current.value; + boundsTL.y += tiledImage._ySpring.current.value; + + var boundsSize = tile.bounds.getSize(); + + boundsSize.x *= tiledImage._scaleSpring.current.value; + boundsSize.y *= tiledImage._scaleSpring.current.value; + + var positionC = viewport.pixelFromPointNoRotate(boundsTL, true), + positionT = viewport.pixelFromPointNoRotate(boundsTL, false), + sizeC = viewport.deltaPixelsFromPointsNoRotate(boundsSize, true), + sizeT = viewport.deltaPixelsFromPointsNoRotate(boundsSize, false), + tileCenter = positionT.plus( sizeT.divide( 2 ) ), + tileSquaredDistance = viewportCenter.squaredDistanceTo( tileCenter ); + + if ( !overlap ) { + sizeC = sizeC.plus( new $.Point( 1, 1 ) ); + } + + if (tile.isRightMost && tiledImage.wrapHorizontal) { + sizeC.x += 0.75; // Otherwise Firefox and Safari show seams + } + + if (tile.isBottomMost && tiledImage.wrapVertical) { + sizeC.y += 0.75; // Otherwise Firefox and Safari show seams + } + + tile.position = positionC; + tile.size = sizeC; + tile.squaredDistance = tileSquaredDistance; + tile.visibility = levelVisibility; +} + +/** + * @private + * @inner + * Updates the opacity of a tile according to the time it has been on screen + * to perform a fade-in. + * Updates coverage once a tile is fully opaque. + * Returns whether the fade-in has completed. + * + * @param {OpenSeadragon.TiledImage} tiledImage + * @param {OpenSeadragon.Tile} tile + * @param {Number} x + * @param {Number} y + * @param {Number} level + * @param {Number} levelOpacity + * @param {Number} currentTime + * @returns {Boolean} + */ +function blendTile( tiledImage, tile, x, y, level, levelOpacity, currentTime ){ + var blendTimeMillis = 1000 * tiledImage.blendTime, + deltaTime, + opacity; + + if ( !tile.blendStart ) { + tile.blendStart = currentTime; + } + + deltaTime = currentTime - tile.blendStart; + opacity = blendTimeMillis ? Math.min( 1, deltaTime / ( blendTimeMillis ) ) : 1; + + if ( tiledImage.alwaysBlend ) { + opacity *= levelOpacity; + } + + tile.opacity = opacity; + + tiledImage.lastDrawn.push( tile ); + + if ( opacity == 1 ) { + setCoverage( tiledImage.coverage, level, x, y, true ); + tiledImage._hasOpaqueTile = true; + } else if ( deltaTime < blendTimeMillis ) { + return true; + } + + return false; +} + +/** + * @private + * @inner + * Returns true if the given tile provides coverage to lower-level tiles of + * lower resolution representing the same content. If neither x nor y is + * given, returns true if the entire visible level provides coverage. + * + * Note that out-of-bounds tiles provide coverage in this sense, since + * there's no content that they would need to cover. Tiles at non-existent + * levels that are within the image bounds, however, do not. + * + * @param {Object} coverage - A '3d' dictionary [level][x][y] --> Boolean. + * @param {Number} level - The resolution level of the tile. + * @param {Number} x - The X position of the tile. + * @param {Number} y - The Y position of the tile. + * @returns {Boolean} + */ +function providesCoverage( coverage, level, x, y ) { + var rows, + cols, + i, j; + + if ( !coverage[ level ] ) { + return false; + } + + if ( x === undefined || y === undefined ) { + rows = coverage[ level ]; + for ( i in rows ) { + if ( rows.hasOwnProperty( i ) ) { + cols = rows[ i ]; + for ( j in cols ) { + if ( cols.hasOwnProperty( j ) && !cols[ j ] ) { + return false; + } + } + } + } + + return true; + } + + return ( + coverage[ level ][ x] === undefined || + coverage[ level ][ x ][ y ] === undefined || + coverage[ level ][ x ][ y ] === true + ); +} + +/** + * @private + * @inner + * Returns true if the given tile is completely covered by higher-level + * tiles of higher resolution representing the same content. If neither x + * nor y is given, returns true if the entire visible level is covered. + * + * @param {Object} coverage - A '3d' dictionary [level][x][y] --> Boolean. + * @param {Number} level - The resolution level of the tile. + * @param {Number} x - The X position of the tile. + * @param {Number} y - The Y position of the tile. + * @returns {Boolean} + */ +function isCovered( coverage, level, x, y ) { + if ( x === undefined || y === undefined ) { + return providesCoverage( coverage, level + 1 ); + } else { + return ( + providesCoverage( coverage, level + 1, 2 * x, 2 * y ) && + providesCoverage( coverage, level + 1, 2 * x, 2 * y + 1 ) && + providesCoverage( coverage, level + 1, 2 * x + 1, 2 * y ) && + providesCoverage( coverage, level + 1, 2 * x + 1, 2 * y + 1 ) + ); + } +} + +/** + * @private + * @inner + * Sets whether the given tile provides coverage or not. + * + * @param {Object} coverage - A '3d' dictionary [level][x][y] --> Boolean. + * @param {Number} level - The resolution level of the tile. + * @param {Number} x - The X position of the tile. + * @param {Number} y - The Y position of the tile. + * @param {Boolean} covers - Whether the tile provides coverage. + */ +function setCoverage( coverage, level, x, y, covers ) { + if ( !coverage[ level ] ) { + $.console.warn( + "Setting coverage for a tile before its level's coverage has been reset: %s", + level + ); + return; + } + + if ( !coverage[ level ][ x ] ) { + coverage[ level ][ x ] = {}; + } + + coverage[ level ][ x ][ y ] = covers; +} + +/** + * @private + * @inner + * Resets coverage information for the given level. This should be called + * after every draw routine. Note that at the beginning of the next draw + * routine, coverage for every visible tile should be explicitly set. + * + * @param {Object} coverage - A '3d' dictionary [level][x][y] --> Boolean. + * @param {Number} level - The resolution level of tiles to completely reset. + */ +function resetCoverage( coverage, level ) { + coverage[ level ] = {}; +} + +/** + * @private + * @inner + * Determines whether the 'last best' tile for the area is better than the + * tile in question. + * + * @param {OpenSeadragon.Tile} previousBest + * @param {OpenSeadragon.Tile} tile + * @returns {OpenSeadragon.Tile} The new best tile. + */ +function compareTiles( previousBest, tile ) { + if ( !previousBest ) { + return tile; + } + + if ( tile.visibility > previousBest.visibility ) { + return tile; + } else if ( tile.visibility == previousBest.visibility ) { + if ( tile.squaredDistance < previousBest.squaredDistance ) { + return tile; + } + } + + return previousBest; +} + +/** + * @private + * @inner + * Draws a TiledImage. + * @param {OpenSeadragon.TiledImage} tiledImage + * @param {OpenSeadragon.Tile[]} lastDrawn - An unordered list of Tiles drawn last frame. + */ +function drawTiles( tiledImage, lastDrawn ) { + if (tiledImage.opacity === 0 || (lastDrawn.length === 0 && !tiledImage.placeholderFillStyle)) { + return; + } + + var tile = lastDrawn[0]; + var useSketch; + + if (tile) { + useSketch = tiledImage.opacity < 1 || + (tiledImage.compositeOperation && + tiledImage.compositeOperation !== 'source-over') || + (!tiledImage._isBottomItem() && tile._hasTransparencyChannel()); + } + + var sketchScale; + var sketchTranslate; + + var zoom = tiledImage.viewport.getZoom(true); + var imageZoom = tiledImage.viewportToImageZoom(zoom); + + if (lastDrawn.length > 1 && + imageZoom > tiledImage.smoothTileEdgesMinZoom && + !tiledImage.iOSDevice && + tiledImage.getRotation(true) % 360 === 0 && // TODO: support tile edge smoothing with tiled image rotation. + $.supportsCanvas) { + // When zoomed in a lot (>100%) the tile edges are visible. + // So we have to composite them at ~100% and scale them up together. + // Note: Disabled on iOS devices per default as it causes a native crash + useSketch = true; + sketchScale = tile.getScaleForEdgeSmoothing(); + sketchTranslate = tile.getTranslationForEdgeSmoothing(sketchScale, + tiledImage._drawer.getCanvasSize(false), + tiledImage._drawer.getCanvasSize(true)); + } + + var bounds; + if (useSketch) { + if (!sketchScale) { + // Except when edge smoothing, we only clean the part of the + // sketch canvas we are going to use for performance reasons. + bounds = tiledImage.viewport.viewportToViewerElementRectangle( + tiledImage.getClippedBounds(true)) + .getIntegerBoundingBox() + .times($.pixelDensityRatio); + } + tiledImage._drawer._clear(true, bounds); + } + + // When scaling, we must rotate only when blending the sketch canvas to + // avoid interpolation + if (!sketchScale) { + if (tiledImage.viewport.degrees !== 0) { + tiledImage._drawer._offsetForRotation({ + degrees: tiledImage.viewport.degrees, + useSketch: useSketch + }); + } + if (tiledImage.getRotation(true) % 360 !== 0) { + tiledImage._drawer._offsetForRotation({ + degrees: tiledImage.getRotation(true), + point: tiledImage.viewport.pixelFromPointNoRotate( + tiledImage._getRotationPoint(true), true), + useSketch: useSketch + }); + } + } + + var usedClip = false; + if ( tiledImage._clip ) { + tiledImage._drawer.saveContext(useSketch); + + var box = tiledImage.imageToViewportRectangle(tiledImage._clip, true); + box = box.rotate(-tiledImage.getRotation(true), tiledImage._getRotationPoint(true)); + var clipRect = tiledImage._drawer.viewportToDrawerRectangle(box); + if (sketchScale) { + clipRect = clipRect.times(sketchScale); + } + if (sketchTranslate) { + clipRect = clipRect.translate(sketchTranslate); + } + tiledImage._drawer.setClip(clipRect, useSketch); + + usedClip = true; + } + + if ( tiledImage.placeholderFillStyle && tiledImage._hasOpaqueTile === false ) { + var placeholderRect = tiledImage._drawer.viewportToDrawerRectangle(tiledImage.getBounds(true)); + if (sketchScale) { + placeholderRect = placeholderRect.times(sketchScale); + } + if (sketchTranslate) { + placeholderRect = placeholderRect.translate(sketchTranslate); + } + + var fillStyle = null; + if ( typeof tiledImage.placeholderFillStyle === "function" ) { + fillStyle = tiledImage.placeholderFillStyle(tiledImage, tiledImage._drawer.context); + } + else { + fillStyle = tiledImage.placeholderFillStyle; + } + + tiledImage._drawer.drawRectangle(placeholderRect, fillStyle, useSketch); + } + + for (var i = lastDrawn.length - 1; i >= 0; i--) { + tile = lastDrawn[ i ]; + tiledImage._drawer.drawTile( tile, tiledImage._drawingHandler, useSketch, sketchScale, sketchTranslate ); + tile.beingDrawn = true; + + if( tiledImage.viewer ){ + /** + * - Needs documentation - + * + * @event tile-drawn + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. + * @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn. + * @property {OpenSeadragon.Tile} tile + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + tiledImage.viewer.raiseEvent( 'tile-drawn', { + tiledImage: tiledImage, + tile: tile + }); + } + } + + if ( usedClip ) { + tiledImage._drawer.restoreContext( useSketch ); + } + + if (!sketchScale) { + if (tiledImage.getRotation(true) % 360 !== 0) { + tiledImage._drawer._restoreRotationChanges(useSketch); + } + if (tiledImage.viewport.degrees !== 0) { + tiledImage._drawer._restoreRotationChanges(useSketch); + } + } + + if (useSketch) { + if (sketchScale) { + if (tiledImage.viewport.degrees !== 0) { + tiledImage._drawer._offsetForRotation({ + degrees: tiledImage.viewport.degrees, + useSketch: false + }); + } + if (tiledImage.getRotation(true) % 360 !== 0) { + tiledImage._drawer._offsetForRotation({ + degrees: tiledImage.getRotation(true), + point: tiledImage.viewport.pixelFromPointNoRotate( + tiledImage._getRotationPoint(true), true), + useSketch: false + }); + } + } + tiledImage._drawer.blendSketch({ + opacity: tiledImage.opacity, + scale: sketchScale, + translate: sketchTranslate, + compositeOperation: tiledImage.compositeOperation, + bounds: bounds + }); + if (sketchScale) { + if (tiledImage.getRotation(true) % 360 !== 0) { + tiledImage._drawer._restoreRotationChanges(false); + } + if (tiledImage.viewport.degrees !== 0) { + tiledImage._drawer._restoreRotationChanges(false); + } + } + } + drawDebugInfo( tiledImage, lastDrawn ); +} + +/** + * @private + * @inner + * Draws special debug information for a TiledImage if in debug mode. + * @param {OpenSeadragon.TiledImage} tiledImage + * @param {OpenSeadragon.Tile[]} lastDrawn - An unordered list of Tiles drawn last frame. + */ +function drawDebugInfo( tiledImage, lastDrawn ) { + if( tiledImage.debugMode ) { + for ( var i = lastDrawn.length - 1; i >= 0; i-- ) { + var tile = lastDrawn[ i ]; + try { + tiledImage._drawer.drawDebugInfo( + tile, lastDrawn.length, i, tiledImage); + } catch(e) { + $.console.error(e); + } + } + } +} + +}( OpenSeadragon )); + +/* + * OpenSeadragon - TileCache + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +// private class +var TileRecord = function( options ) { + $.console.assert( options, "[TileCache.cacheTile] options is required" ); + $.console.assert( options.tile, "[TileCache.cacheTile] options.tile is required" ); + $.console.assert( options.tiledImage, "[TileCache.cacheTile] options.tiledImage is required" ); + this.tile = options.tile; + this.tiledImage = options.tiledImage; +}; + +// private class +var ImageRecord = function(options) { + $.console.assert( options, "[ImageRecord] options is required" ); + $.console.assert( options.image, "[ImageRecord] options.image is required" ); + this._image = options.image; + this._tiles = []; +}; + +ImageRecord.prototype = { + destroy: function() { + this._image = null; + this._renderedContext = null; + this._tiles = null; + }, + + getImage: function() { + return this._image; + }, + + getRenderedContext: function() { + if (!this._renderedContext) { + var canvas = document.createElement( 'canvas' ); + canvas.width = this._image.width; + canvas.height = this._image.height; + this._renderedContext = canvas.getContext('2d'); + this._renderedContext.drawImage( this._image, 0, 0 ); + //since we are caching the prerendered image on a canvas + //allow the image to not be held in memory + this._image = null; + } + return this._renderedContext; + }, + + setRenderedContext: function(renderedContext) { + $.console.error("ImageRecord.setRenderedContext is deprecated. " + + "The rendered context should be created by the ImageRecord " + + "itself when calling ImageRecord.getRenderedContext."); + this._renderedContext = renderedContext; + }, + + addTile: function(tile) { + $.console.assert(tile, '[ImageRecord.addTile] tile is required'); + this._tiles.push(tile); + }, + + removeTile: function(tile) { + for (var i = 0; i < this._tiles.length; i++) { + if (this._tiles[i] === tile) { + this._tiles.splice(i, 1); + return; + } + } + + $.console.warn('[ImageRecord.removeTile] trying to remove unknown tile', tile); + }, + + getTileCount: function() { + return this._tiles.length; + } +}; + +/** + * @class TileCache + * @memberof OpenSeadragon + * @classdesc Stores all the tiles displayed in a {@link OpenSeadragon.Viewer}. + * You generally won't have to interact with the TileCache directly. + * @param {Object} options - Configuration for this TileCache. + * @param {Number} [options.maxImageCacheCount] - See maxImageCacheCount in + * {@link OpenSeadragon.Options} for details. + */ +$.TileCache = function( options ) { + options = options || {}; + + this._maxImageCacheCount = options.maxImageCacheCount || $.DEFAULT_SETTINGS.maxImageCacheCount; + this._tilesLoaded = []; + this._imagesLoaded = []; + this._imagesLoadedCount = 0; +}; + +/** @lends OpenSeadragon.TileCache.prototype */ +$.TileCache.prototype = { + /** + * @returns {Number} The total number of tiles that have been loaded by + * this TileCache. + */ + numTilesLoaded: function() { + return this._tilesLoaded.length; + }, + + /** + * Caches the specified tile, removing an old tile if necessary to stay under the + * maxImageCacheCount specified on construction. Note that if multiple tiles reference + * the same image, there may be more tiles than maxImageCacheCount; the goal is to keep + * the number of images below that number. Note, as well, that even the number of images + * may temporarily surpass that number, but should eventually come back down to the max specified. + * @param {Object} options - Tile info. + * @param {OpenSeadragon.Tile} options.tile - The tile to cache. + * @param {String} options.tile.cacheKey - The unique key used to identify this tile in the cache. + * @param {Image} options.image - The image of the tile to cache. + * @param {OpenSeadragon.TiledImage} options.tiledImage - The TiledImage that owns that tile. + * @param {Number} [options.cutoff=0] - If adding this tile goes over the cache max count, this + * function will release an old tile. The cutoff option specifies a tile level at or below which + * tiles will not be released. + */ + cacheTile: function( options ) { + $.console.assert( options, "[TileCache.cacheTile] options is required" ); + $.console.assert( options.tile, "[TileCache.cacheTile] options.tile is required" ); + $.console.assert( options.tile.cacheKey, "[TileCache.cacheTile] options.tile.cacheKey is required" ); + $.console.assert( options.tiledImage, "[TileCache.cacheTile] options.tiledImage is required" ); + + var cutoff = options.cutoff || 0; + var insertionIndex = this._tilesLoaded.length; + + var imageRecord = this._imagesLoaded[options.tile.cacheKey]; + if (!imageRecord) { + $.console.assert( options.image, "[TileCache.cacheTile] options.image is required to create an ImageRecord" ); + imageRecord = this._imagesLoaded[options.tile.cacheKey] = new ImageRecord({ + image: options.image + }); + + this._imagesLoadedCount++; + } + + imageRecord.addTile(options.tile); + options.tile.cacheImageRecord = imageRecord; + + // Note that just because we're unloading a tile doesn't necessarily mean + // we're unloading an image. With repeated calls it should sort itself out, though. + if ( this._imagesLoadedCount > this._maxImageCacheCount ) { + var worstTile = null; + var worstTileIndex = -1; + var worstTileRecord = null; + var prevTile, worstTime, worstLevel, prevTime, prevLevel, prevTileRecord; + + for ( var i = this._tilesLoaded.length - 1; i >= 0; i-- ) { + prevTileRecord = this._tilesLoaded[ i ]; + prevTile = prevTileRecord.tile; + + if ( prevTile.level <= cutoff || prevTile.beingDrawn ) { + continue; + } else if ( !worstTile ) { + worstTile = prevTile; + worstTileIndex = i; + worstTileRecord = prevTileRecord; + continue; + } + + prevTime = prevTile.lastTouchTime; + worstTime = worstTile.lastTouchTime; + prevLevel = prevTile.level; + worstLevel = worstTile.level; + + if ( prevTime < worstTime || + ( prevTime == worstTime && prevLevel > worstLevel ) ) { + worstTile = prevTile; + worstTileIndex = i; + worstTileRecord = prevTileRecord; + } + } + + if ( worstTile && worstTileIndex >= 0 ) { + this._unloadTile(worstTileRecord); + insertionIndex = worstTileIndex; + } + } + + this._tilesLoaded[ insertionIndex ] = new TileRecord({ + tile: options.tile, + tiledImage: options.tiledImage + }); + }, + + /** + * Clears all tiles associated with the specified tiledImage. + * @param {OpenSeadragon.TiledImage} tiledImage + */ + clearTilesFor: function( tiledImage ) { + $.console.assert(tiledImage, '[TileCache.clearTilesFor] tiledImage is required'); + var tileRecord; + for ( var i = 0; i < this._tilesLoaded.length; ++i ) { + tileRecord = this._tilesLoaded[ i ]; + if ( tileRecord.tiledImage === tiledImage ) { + this._unloadTile(tileRecord); + this._tilesLoaded.splice( i, 1 ); + i--; + } + } + }, + + // private + getImageRecord: function(cacheKey) { + $.console.assert(cacheKey, '[TileCache.getImageRecord] cacheKey is required'); + return this._imagesLoaded[cacheKey]; + }, + + // private + _unloadTile: function(tileRecord) { + $.console.assert(tileRecord, '[TileCache._unloadTile] tileRecord is required'); + var tile = tileRecord.tile; + var tiledImage = tileRecord.tiledImage; + + tile.unload(); + tile.cacheImageRecord = null; + + var imageRecord = this._imagesLoaded[tile.cacheKey]; + imageRecord.removeTile(tile); + if (!imageRecord.getTileCount()) { + imageRecord.destroy(); + delete this._imagesLoaded[tile.cacheKey]; + this._imagesLoadedCount--; + } + + /** + * Triggered when a tile has just been unloaded from memory. + * + * @event tile-unloaded + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image of the unloaded tile. + * @property {OpenSeadragon.Tile} tile - The tile which has been unloaded. + */ + tiledImage.viewer.raiseEvent("tile-unloaded", { + tile: tile, + tiledImage: tiledImage + }); + } +}; + +}( OpenSeadragon )); + +/* + * OpenSeadragon - World + * + * Copyright (C) 2009 CodePlex Foundation + * Copyright (C) 2010-2013 OpenSeadragon contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of CodePlex Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function( $ ){ + +/** + * @class World + * @memberof OpenSeadragon + * @extends OpenSeadragon.EventSource + * @classdesc Keeps track of all of the tiled images in the scene. + * @param {Object} options - World options. + * @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this World. + **/ +$.World = function( options ) { + var _this = this; + + $.console.assert( options.viewer, "[World] options.viewer is required" ); + + $.EventSource.call( this ); + + this.viewer = options.viewer; + this._items = []; + this._needsDraw = false; + this._autoRefigureSizes = true; + this._needsSizesFigured = false; + this._delegatedFigureSizes = function(event) { + if (_this._autoRefigureSizes) { + _this._figureSizes(); + } else { + _this._needsSizesFigured = true; + } + }; + + this._figureSizes(); +}; + +$.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.World.prototype */{ + /** + * Add the specified item. + * @param {OpenSeadragon.TiledImage} item - The item to add. + * @param {Number} [options.index] - Index for the item. If not specified, goes at the top. + * @fires OpenSeadragon.World.event:add-item + * @fires OpenSeadragon.World.event:metrics-change + */ + addItem: function( item, options ) { + $.console.assert(item, "[World.addItem] item is required"); + $.console.assert(item instanceof $.TiledImage, "[World.addItem] only TiledImages supported at this time"); + + options = options || {}; + if (options.index !== undefined) { + var index = Math.max(0, Math.min(this._items.length, options.index)); + this._items.splice(index, 0, item); + } else { + this._items.push( item ); + } + + if (this._autoRefigureSizes) { + this._figureSizes(); + } else { + this._needsSizesFigured = true; + } + + this._needsDraw = true; + + item.addHandler('bounds-change', this._delegatedFigureSizes); + item.addHandler('clip-change', this._delegatedFigureSizes); + + /** + * Raised when an item is added to the World. + * @event add-item + * @memberOf OpenSeadragon.World + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the World which raised the event. + * @property {OpenSeadragon.TiledImage} item - The item that has been added. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'add-item', { + item: item + } ); + }, + + /** + * Get the item at the specified index. + * @param {Number} index - The item's index. + * @returns {OpenSeadragon.TiledImage} The item at the specified index. + */ + getItemAt: function( index ) { + $.console.assert(index !== undefined, "[World.getItemAt] index is required"); + return this._items[ index ]; + }, + + /** + * Get the index of the given item or -1 if not present. + * @param {OpenSeadragon.TiledImage} item - The item. + * @returns {Number} The index of the item or -1 if not present. + */ + getIndexOfItem: function( item ) { + $.console.assert(item, "[World.getIndexOfItem] item is required"); + return $.indexOf( this._items, item ); + }, + + /** + * @returns {Number} The number of items used. + */ + getItemCount: function() { + return this._items.length; + }, + + /** + * Change the index of a item so that it appears over or under others. + * @param {OpenSeadragon.TiledImage} item - The item to move. + * @param {Number} index - The new index. + * @fires OpenSeadragon.World.event:item-index-change + */ + setItemIndex: function( item, index ) { + $.console.assert(item, "[World.setItemIndex] item is required"); + $.console.assert(index !== undefined, "[World.setItemIndex] index is required"); + + var oldIndex = this.getIndexOfItem( item ); + + if ( index >= this._items.length ) { + throw new Error( "Index bigger than number of layers." ); + } + + if ( index === oldIndex || oldIndex === -1 ) { + return; + } + + this._items.splice( oldIndex, 1 ); + this._items.splice( index, 0, item ); + this._needsDraw = true; + + /** + * Raised when the order of the indexes has been changed. + * @event item-index-change + * @memberOf OpenSeadragon.World + * @type {object} + * @property {OpenSeadragon.World} eventSource - A reference to the World which raised the event. + * @property {OpenSeadragon.TiledImage} item - The item whose index has + * been changed + * @property {Number} previousIndex - The previous index of the item + * @property {Number} newIndex - The new index of the item + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'item-index-change', { + item: item, + previousIndex: oldIndex, + newIndex: index + } ); + }, + + /** + * Remove an item. + * @param {OpenSeadragon.TiledImage} item - The item to remove. + * @fires OpenSeadragon.World.event:remove-item + * @fires OpenSeadragon.World.event:metrics-change + */ + removeItem: function( item ) { + $.console.assert(item, "[World.removeItem] item is required"); + + var index = $.indexOf(this._items, item ); + if ( index === -1 ) { + return; + } + + item.removeHandler('bounds-change', this._delegatedFigureSizes); + item.removeHandler('clip-change', this._delegatedFigureSizes); + item.destroy(); + this._items.splice( index, 1 ); + this._figureSizes(); + this._needsDraw = true; + this._raiseRemoveItem(item); + }, + + /** + * Remove all items. + * @fires OpenSeadragon.World.event:remove-item + * @fires OpenSeadragon.World.event:metrics-change + */ + removeAll: function() { + // We need to make sure any pending images are canceled so the world items don't get messed up + this.viewer._cancelPendingImages(); + var item; + var i; + for (i = 0; i < this._items.length; i++) { + item = this._items[i]; + item.removeHandler('bounds-change', this._delegatedFigureSizes); + item.removeHandler('clip-change', this._delegatedFigureSizes); + item.destroy(); + } + + var removedItems = this._items; + this._items = []; + this._figureSizes(); + this._needsDraw = true; + + for (i = 0; i < removedItems.length; i++) { + item = removedItems[i]; + this._raiseRemoveItem(item); + } + }, + + /** + * Clears all tiles and triggers updates for all items. + */ + resetItems: function() { + for ( var i = 0; i < this._items.length; i++ ) { + this._items[i].reset(); + } + }, + + /** + * Updates (i.e. animates bounds of) all items. + */ + update: function() { + var animated = false; + for ( var i = 0; i < this._items.length; i++ ) { + animated = this._items[i].update() || animated; + } + + return animated; + }, + + /** + * Draws all items. + */ + draw: function() { + for ( var i = 0; i < this._items.length; i++ ) { + this._items[i].draw(); + } + + this._needsDraw = false; + }, + + /** + * @returns {Boolean} true if any items need updating. + */ + needsDraw: function() { + for ( var i = 0; i < this._items.length; i++ ) { + if ( this._items[i].needsDraw() ) { + return true; + } + } + return this._needsDraw; + }, + + /** + * @returns {OpenSeadragon.Rect} The smallest rectangle that encloses all items, in viewport coordinates. + */ + getHomeBounds: function() { + return this._homeBounds.clone(); + }, + + /** + * To facilitate zoom constraints, we keep track of the pixel density of the + * densest item in the World (i.e. the item whose content size to viewport size + * ratio is the highest) and save it as this "content factor". + * @returns {Number} the number of content units per viewport unit. + */ + getContentFactor: function() { + return this._contentFactor; + }, + + /** + * As a performance optimization, setting this flag to false allows the bounds-change event handler + * on tiledImages to skip calculations on the world bounds. If a lot of images are going to be positioned in + * rapid succession, this is a good idea. When finished, setAutoRefigureSizes should be called with true + * or the system may behave oddly. + * @param {Boolean} [value] The value to which to set the flag. + */ + setAutoRefigureSizes: function(value) { + this._autoRefigureSizes = value; + if (value & this._needsSizesFigured) { + this._figureSizes(); + this._needsSizesFigured = false; + } + }, + + /** + * Arranges all of the TiledImages with the specified settings. + * @param {Object} options - Specifies how to arrange. + * @param {Boolean} [options.immediately=false] - Whether to animate to the new arrangement. + * @param {String} [options.layout] - See collectionLayout in {@link OpenSeadragon.Options}. + * @param {Number} [options.rows] - See collectionRows in {@link OpenSeadragon.Options}. + * @param {Number} [options.columns] - See collectionColumns in {@link OpenSeadragon.Options}. + * @param {Number} [options.tileSize] - See collectionTileSize in {@link OpenSeadragon.Options}. + * @param {Number} [options.tileMargin] - See collectionTileMargin in {@link OpenSeadragon.Options}. + * @fires OpenSeadragon.World.event:metrics-change + */ + arrange: function(options) { + options = options || {}; + var immediately = options.immediately || false; + var layout = options.layout || $.DEFAULT_SETTINGS.collectionLayout; + var rows = options.rows || $.DEFAULT_SETTINGS.collectionRows; + var columns = options.columns || $.DEFAULT_SETTINGS.collectionColumns; + var tileSize = options.tileSize || $.DEFAULT_SETTINGS.collectionTileSize; + var tileMargin = options.tileMargin || $.DEFAULT_SETTINGS.collectionTileMargin; + var increment = tileSize + tileMargin; + var wrap; + if (!options.rows && columns) { + wrap = columns; + } else { + wrap = Math.ceil(this._items.length / rows); + } + var x = 0; + var y = 0; + var item, box, width, height, position; + + this.setAutoRefigureSizes(false); + for (var i = 0; i < this._items.length; i++) { + if (i && (i % wrap) === 0) { + if (layout === 'horizontal') { + y += increment; + x = 0; + } else { + x += increment; + y = 0; + } + } + + item = this._items[i]; + box = item.getBounds(); + if (box.width > box.height) { + width = tileSize; + } else { + width = tileSize * (box.width / box.height); + } + + height = width * (box.height / box.width); + position = new $.Point(x + ((tileSize - width) / 2), + y + ((tileSize - height) / 2)); + + item.setPosition(position, immediately); + item.setWidth(width, immediately); + + if (layout === 'horizontal') { + x += increment; + } else { + y += increment; + } + } + this.setAutoRefigureSizes(true); + }, + + // private + _figureSizes: function() { + var oldHomeBounds = this._homeBounds ? this._homeBounds.clone() : null; + var oldContentSize = this._contentSize ? this._contentSize.clone() : null; + var oldContentFactor = this._contentFactor || 0; + + if (!this._items.length) { + this._homeBounds = new $.Rect(0, 0, 1, 1); + this._contentSize = new $.Point(1, 1); + this._contentFactor = 1; + } else { + var item = this._items[0]; + var bounds = item.getBounds(); + this._contentFactor = item.getContentSize().x / bounds.width; + var clippedBounds = item.getClippedBounds().getBoundingBox(); + var left = clippedBounds.x; + var top = clippedBounds.y; + var right = clippedBounds.x + clippedBounds.width; + var bottom = clippedBounds.y + clippedBounds.height; + for (var i = 1; i < this._items.length; i++) { + item = this._items[i]; + bounds = item.getBounds(); + this._contentFactor = Math.max(this._contentFactor, + item.getContentSize().x / bounds.width); + clippedBounds = item.getClippedBounds().getBoundingBox(); + left = Math.min(left, clippedBounds.x); + top = Math.min(top, clippedBounds.y); + right = Math.max(right, clippedBounds.x + clippedBounds.width); + bottom = Math.max(bottom, clippedBounds.y + clippedBounds.height); + } + + this._homeBounds = new $.Rect(left, top, right - left, bottom - top); + this._contentSize = new $.Point( + this._homeBounds.width * this._contentFactor, + this._homeBounds.height * this._contentFactor); + } + + if (this._contentFactor !== oldContentFactor || + !this._homeBounds.equals(oldHomeBounds) || + !this._contentSize.equals(oldContentSize)) { + /** + * Raised when the home bounds or content factor change. + * @event metrics-change + * @memberOf OpenSeadragon.World + * @type {object} + * @property {OpenSeadragon.World} eventSource - A reference to the World which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('metrics-change', {}); + } + }, + + // private + _raiseRemoveItem: function(item) { + /** + * Raised when an item is removed. + * @event remove-item + * @memberOf OpenSeadragon.World + * @type {object} + * @property {OpenSeadragon.World} eventSource - A reference to the World which raised the event. + * @property {OpenSeadragon.TiledImage} item - The item's underlying item. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'remove-item', { item: item } ); + } +}); + +}( OpenSeadragon )); + +//# sourceMappingURL=openseadragon.js.map \ No newline at end of file diff --git a/js/openseadragon/openseadragon-bin-2.3.1/openseadragon.js.map b/js/openseadragon/openseadragon-bin-2.3.1/openseadragon.js.map new file mode 100644 index 000000000..7b3b364f2 --- /dev/null +++ b/js/openseadragon/openseadragon-bin-2.3.1/openseadragon.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/openseadragon.js","../../src/fullscreen.js","../../src/eventsource.js","../../src/mousetracker.js","../../src/control.js","../../src/controldock.js","../../src/placement.js","../../src/viewer.js","../../src/navigator.js","../../src/strings.js","../../src/point.js","../../src/tilesource.js","../../src/dzitilesource.js","../../src/iiiftilesource.js","../../src/osmtilesource.js","../../src/tmstilesource.js","../../src/zoomifytilesource.js","../../src/legacytilesource.js","../../src/imagetilesource.js","../../src/tilesourcecollection.js","../../src/button.js","../../src/buttongroup.js","../../src/rectangle.js","../../src/referencestrip.js","../../src/displayrectangle.js","../../src/spring.js","../../src/imageloader.js","../../src/tile.js","../../src/overlay.js","../../src/drawer.js","../../src/viewport.js","../../src/tiledimage.js","../../src/tilecache.js","../../src/world.js"],"names":[],"mappings":";;;;;;AAAA,EAAE;AACF,CAAC,CAAC,CAAC,aAAa;AAChB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,EAAE;AACF,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;AAClD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,GAAG;AAClE,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,SAAS;AACtE,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;AACtE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE;AACrE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE;AACxE,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;AACjE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;AAClE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAClE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE;AACrE,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG;AACxD,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM;AACzE,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU;AACxE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;AAClE,CAAC,EAAE;AACH;AACA,EAAE;AACF,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;AACtC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AAC1E,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,GAAG;AAC7E,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU;AAC5E,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC;AAC3E,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AACvE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ;AAC1E,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;AACzD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO;AAC1E,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE;AAC7D,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;AACzE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG;AACvE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI;AAC5E,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;AAC3E,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC7C,CAAC,EAAE;AACH;AACA;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa;AAC3B,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO;AACxE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;AACtD,CAAC,CAAC;AACF,CAAC,EAAE;AACH;AACA;AACA,EAAE,CAAC,QAAQ;AACX;AACA,CAAC,GAAG;AACJ,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC;AACzG,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAC7B,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC3B,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AACzB,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC;AAChI,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpI,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AAC/B,EAAE,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC;AACrH,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpI,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC;AAC/D,EAAE,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,GAAG;AAC1E,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AACtD,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AACnC,EAAE,CAAC,KAAK,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACjI,EAAE,CAAC,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;AACvF,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE;AAC9E,EAAE,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI;AAC7E,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG;AAChF,EAAE,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC;AACxB,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG;AACvE,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC;AAC/C,EAAE,CAAC,KAAK,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU;AAC1E,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACxE,EAAE,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;AAClC,EAAE,CAAC,KAAK,QAAQ,CAAC,UAAU,CAAC;AAC5B,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;AACzE,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK;AACnF,EAAE,CAAC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;AAC9E,EAAE,CAAC,OAAO,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE;AACxF,EAAE,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO;AACvD,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;AACnF,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;AACnF,EAAE,CAAC,OAAO,OAAO,CAAC;AAClB,EAAE,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC7E,EAAE,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE;AAC9E,EAAE,CAAC,OAAO,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;AAClE,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;AACrC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;AACxF,EAAE,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC;AAC7C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,GAAG,MAAM,GAAG;AAC7C,EAAE,CAAC,KAAK,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM;AACvE,EAAE,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU;AAChE,EAAE,CAAC,KAAK,YAAY,CAAC;AACrB,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AACnD,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU;AAC9E,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;AAC5E,EAAE,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AACjF,EAAE,CAAC,KAAK,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,GAAG;AAChF,EAAE,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI;AACjF,EAAE,CAAC,KAAK,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM;AAC9E,EAAE,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU;AAC/E,EAAE,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;AACvD,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AACzC,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC;AACzE,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,IAAI,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG;AAC3I,EAAE,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC;AAC5F,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC;AAC1F,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AACpC,EAAE,CAAC,KAAK,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG;AAC9E,EAAE,CAAC,KAAK,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;AACpC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC;AAC3C,EAAE,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ;AAC5E,EAAE,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK;AAC7E,EAAE,CAAC,KAAK,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AAC/B,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC;AAC/C,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU;AAC5E,EAAE,CAAC,KAAK,QAAQ,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO;AAC5E,EAAE,CAAC,KAAK,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;AACxD,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC;AAC/C,EAAE,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK;AAC/E,EAAE,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM;AAC/E,EAAE,CAAC,KAAK,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;AAC3C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAC3C,EAAE,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC;AACnF,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AACpC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAClC,EAAE,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AAC7E,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC;AAC3E,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AACvC,EAAE,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;AAC3E,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC;AAChD,EAAE,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE;AACjF,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,EAAE;AACjE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC;AACrD,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,oBAAoB,CAAC,IAAI,CAAC;AACxF,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC;AAC1E,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE;AACtD,EAAE,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC;AAChJ,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAClC,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC;AACzB,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC;AAC1C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC;AAC1C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC;AAC/C,EAAE,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO;AAC1E,EAAE,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC;AAC5D,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC;AAC5C,EAAE,CAAC,KAAK,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;AAC7B,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC;AAC1C,EAAE,CAAC,KAAK,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;AAC3B,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,CAAC;AAClD,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC;AAC9C,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;AAChF,EAAE,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC;AACnF,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC;AAC5C,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC9E,EAAE,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC;AACnF,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,EAAE,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC3E,EAAE,CAAC,KAAK,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC;AAC/E,EAAE,CAAC,KAAK,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;AACzE,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,EAAE,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK;AAC9E,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG;AAC/E,EAAE,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AAC7E,EAAE,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;AACvC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC;AAC9E,EAAE,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;AAChF,EAAE,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC;AAChF,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC;AAC9C,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,EAAE;AAC/I,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG;AACrC,EAAE,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AAC1D,EAAE,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AAChF,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;AACzC,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC;AAC7G,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB,CAAC,KAAK,CAAC;AACzD,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE;AACzH,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,EAAE,CAAC;AAC9C,EAAE,CAAC,KAAK,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM;AACjH,EAAE,CAAC,KAAK,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO;AACjH,EAAE,CAAC,KAAK,IAAI,CAAC,UAAU,CAAC;AACxB,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,EAAE,CAAC;AAC9C,EAAE,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;AAC9F,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,EAAE,CAAC,KAAK,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK;AAC5E,EAAE,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI;AAC9E,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE;AAC1E,EAAE,CAAC,KAAK,QAAQ,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE;AAC9E,EAAE,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC;AACzE,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,IAAI;AAC3C,EAAE,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC;AAC5E,EAAE,CAAC,KAAK,QAAQ,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;AAC1F,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAC3C,EAAE,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,OAAO;AAC7E,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;AACzE,EAAE,CAAC,KAAK,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;AACrE,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC;AAC/C,EAAE,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW;AACpF,EAAE,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC5C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC;AAC7C,EAAE,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK;AACzF,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC1C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,GAAG,CAAC;AAClD,EAAE,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACvF,EAAE,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;AACnD,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,EAAE,CAAC;AACjD,EAAE,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM;AACtE,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;AACjD,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1C,EAAE,CAAC,KAAK,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC;AAC9E,EAAE,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC;AACxD,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC,oBAAoB,CAAC;AACpE,EAAE,CAAC,KAAK,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,eAAe,EAAE;AAC9G,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO;AACzF,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO;AACvF,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACxH,EAAE,CAAC,KAAK,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;AAC1E,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO;AACxF,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO;AACxF,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,oBAAoB,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;AAC5J,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO;AACrI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;AAClK,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC,oBAAoB,CAAC;AACpE,EAAE,CAAC,KAAK,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,eAAe,EAAE;AAC9G,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO;AAC1F,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO;AACxF,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACvH,EAAE,CAAC,KAAK,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;AAC1E,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO;AACvF,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO;AACvF,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,oBAAoB,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;AAC5J,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO;AACrI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;AAClK,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC,kBAAkB,CAAC;AAClE,EAAE,CAAC,KAAK,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,eAAe,EAAE;AAC5G,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO;AACxF,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO;AACrF,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACtH,EAAE,CAAC,KAAK,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;AAC1E,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO;AACtF,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO;AACtF,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;AAC1J,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO;AACnI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;AAChK,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC,sBAAsB,CAAC;AACtE,EAAE,CAAC,KAAK,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,eAAe,EAAE;AAC/G,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO;AAC3F,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO;AAC1F,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACzH,EAAE,CAAC,KAAK,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;AAC1E,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO;AACzF,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO;AACzF,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,sBAAsB,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;AAC9J,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,sBAAsB,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO;AACvI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;AACpK,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,WAAW,CAAC,cAAc,IAAI,EAAE,CAAC;AACpO,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1C,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,YAAY,KAAK,EAAE,CAAC;AAC7N,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1C,EAAE,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;AAClE,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AAC7C,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC;AACzD,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC;AAC7D,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC;AACtD,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,kBAAkB,CAAC,CAAC,0BAA0B,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;AACrL,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;AACvG,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB,EAAE,SAAS,EAAE;AACtD,EAAE,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC,QAAQ,GAAG,EAAE,CAAC;AACnG,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,0BAA0B,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;AACzN,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC;AAC7K,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C,EAAE,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC;AACjG,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC,KAAK,CAAC;AAC1D,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;AAC1G,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC;AACjD,EAAE,CAAC,KAAK,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,iBAAiB,EAAE;AAChF,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC;AAClD,EAAE,CAAC,KAAK,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,iBAAiB,EAAE;AAChF,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC;AACpD,EAAE,CAAC,KAAK,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,iBAAiB,EAAE;AAC5E,EAAE,CAAC,KAAK,EAAE,CAAC,SAAS,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,0BAA0B,CAAC,GAAG,CAAC,OAAO,CAAC;AACpF,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC;AACnD,EAAE,CAAC,KAAK,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,iBAAiB,EAAE;AAC5E,EAAE,CAAC,KAAK,EAAE,CAAC,SAAS,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,0BAA0B,CAAC,GAAG,CAAC,OAAO,CAAC;AACpF,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC;AAClD,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC;AAChH,EAAE,CAAC,KAAK,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;AACvG,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC;AAChD,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC;AACpF,EAAE,CAAC,KAAK,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;AACxE,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC;AAC9C,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;AACxE,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC;AAC/C,EAAE,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW;AAChF,EAAE,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,OAAO;AACxE,EAAE,CAAC,KAAK,qBAAqB,CAAC,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;AACjE,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC;AAChD,EAAE,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC;AACtE,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC;AAC/C,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE;AACvE,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AACtC,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC;AAC9E,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC;AACxC,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC;AACvG,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1C,EAAE,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI;AAC7E,EAAE,CAAC,KAAK,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG;AAC3E,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG;AAC/E,EAAE,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC;AAC1C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC;AAC9C,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,OAAO;AAC/E,EAAE,CAAC,KAAK,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM;AAChF,EAAE,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AAChC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,CAAC;AACpD,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,CAAC;AACtF,EAAE,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO;AACzE,EAAE,CAAC,KAAK,YAAY,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;AAC/D,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,uBAAuB,CAAC,QAAQ,CAAC;AAC9E,EAAE,CAAC,KAAK,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;AACrD,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG;AAC9D,EAAE,CAAC,KAAK,qBAAqB,CAAC,MAAM,CAAC;AACrC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC;AAC9C,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC;AAC1E,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,EAAE,CAAC,UAAU;AAC/E,EAAE,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC;AACvC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC;AAC9C,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ;AACjF,EAAE,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC;AACzB,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,EAAE,CAAC,UAAU;AAC/E,EAAE,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC;AACvC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC;AAClD,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM;AACzE,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;AAC9C,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,EAAE,CAAC,UAAU;AAC/E,EAAE,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC;AACvC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,KAAK,CAAC;AACnD,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG;AACpF,EAAE,CAAC,KAAK,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM;AACjF,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,KAAK,EAAE,CAAC;AAC7C,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,EAAE,CAAC,UAAU;AAC/E,EAAE,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC;AACvC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC;AAClD,EAAE,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG;AAChF,EAAE,CAAC,KAAK,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;AACpC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,qBAAqB,CAAC,QAAQ,CAAC;AAC5E,EAAE,CAAC,KAAK,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;AACnD,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC;AAC/C,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI;AAC3E,EAAE,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AAC5E,EAAE,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;AAC1C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY;AACnC,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC;AACzD,EAAE,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;AAC5E,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK;AACxD,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC;AAC/C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa;AACpC,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC;AAC1D,EAAE,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;AAC5E,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK;AACxD,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC;AAC/C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU;AACjC,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC;AACzD,EAAE,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;AAC5E,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK;AACxD,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC;AAC/C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,cAAc;AACrC,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC;AAClE,EAAE,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;AAC5E,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK;AACxD,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC;AAC/C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,gBAAgB;AACvC,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC;AAC7D,EAAE,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;AAC5E,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK;AACxD,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC;AAC/C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,iBAAiB;AACxC,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC;AAC9D,EAAE,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;AAC5E,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK;AACxD,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC;AAC/C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,cAAc;AACrC,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC;AAC/D,EAAE,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;AAC5E,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK;AACxD,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC;AAC/C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU;AACjC,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC;AAC3D,EAAE,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;AAC5E,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK;AACxD,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC;AAC/C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC;AAC5C,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AACxF,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;AACxD,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AACtC,EAAE,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;AAC7D,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC;AAChD,EAAE,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG;AACvF,EAAE,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ;AAC3F,EAAE,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC7E,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC;AAChD,EAAE,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK;AAC5E,EAAE,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC5B,EAAE,CAAC,KAAK,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC;AAChH,EAAE,CAAC,KAAK,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;AACrE,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AACrF,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU;AAClF,EAAE,CAAC,KAAK,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO;AAC/E,EAAE,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC;AAC5C,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,CAAC;AAClD,EAAE,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG;AACvF,EAAE,CAAC,KAAK,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;AACtC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,oBAAoB,EAAE,UAAU,EAAE;AAC1D,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,CAAC;AACpD,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,oBAAoB,CAAC,IAAI,CAAC;AAClD,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC;AACjD,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,sBAAsB,EAAE,WAAW,EAAE;AAC7D,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC;AAC9C,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;AAClF,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;AACzC,EAAE,CAAC,KAAK,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACtG,EAAE,CAAC,KAAK,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;AAC9E,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC;AAC5C,EAAE,CAAC,KAAK,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACzG,EAAE,CAAC,KAAK,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAClI,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,EAAE,UAAU,EAAE;AACtD,EAAE,CAAC,KAAK,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,YAAY,CAAC;AAC3F,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC;AAC/C,EAAE,CAAC,KAAK,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAChH,EAAE,CAAC,KAAK,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC;AAC9E,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,oBAAoB,CAAC,EAAE,CAAC;AAChD,EAAE,CAAC,KAAK,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;AAC1G,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC;AACxD,EAAE,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI;AAClG,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;AACrD,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,KAAK,CAAC;AACnD,EAAE,CAAC,KAAK,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;AACtE,EAAE,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC;AACvF,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC;AACjD,EAAE,CAAC,KAAK,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;AACtD,EAAE,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC;AACvF,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,IAAI;AACvC,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC;AACxF,EAAE,CAAC;AACH,EAAE,EAAE;AACJ;AACA,CAAC,GAAG;AACJ,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACxD,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe;AACrC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC3B,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY;AACpC,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC;AAC3D,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW;AACnC,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC;AAC1D,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,cAAc;AACtC,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACtF,EAAE,CAAC,KAAK,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;AAC1E,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW;AACnC,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC;AAC1D,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY;AACpC,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AAChG,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa;AACpC,EAAE,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AAC5J,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa;AACpC,EAAE,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AACpK,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE;AACpH,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC;AAC1G,EAAE,CAAC;AACH,EAAE,EAAE;AACJ;AACA,GAAG;AACH,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC;AAC5E,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS;AAC/B,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC3B,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;AAC9D,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI;AAClC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK;AACnC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK;AACnC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI;AAClC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;AAChE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI;AACnC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK;AACpC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK;AACpC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI;AACnC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;AACzD,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI;AAChC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK;AACjC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK;AACjC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI;AAChC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AAClE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI;AACpC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK;AACrC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK;AACrC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI;AACpC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AACtE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,IAAI;AACtC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,KAAK;AACvC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,KAAK;AACvC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,IAAI;AACtC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;AACxE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,IAAI;AACvC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,KAAK;AACxC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,KAAK;AACxC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,IAAI;AACvC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;AACjE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI;AACpC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK;AACrC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK;AACrC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI;AACpC,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;AACzD,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI;AAChC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK;AACjC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK;AACjC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI;AAChC,EAAE,CAAC;AACH,EAAE,EAAE;AACJ;AACA;AACA,QAAQ,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,EAAE;AAClC,IAAI,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE;AAC/C,CAAC;AACD;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC;AACjC,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AAC7C,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,QAAQ,GAAG;AAC/F,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;AAC3D,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;AAC3D,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;AACzD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnB,KAAK,EAAE;AACP,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AACjB,QAAQ,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC5B,QAAQ,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;AACjC,QAAQ,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;AACjC,QAAQ,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;AACnC,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK;AAC9B,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,EAAE;AACP,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACtB,YAAY,EAAE,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,EAAE;AAC9C,YAAY,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE;AAC7C,YAAY,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE;AAC7C,YAAY,EAAE,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC/C,YAAY,EAAE,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE;AAC5C,YAAY,EAAE,MAAM,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE;AAC3C,YAAY,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE;AAC7C,YAAY,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AAC5C,QAAQ,EAAE;AACV,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO;AAChD,QAAQ,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC;AAChD,QAAQ,MAAM,MAAM,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC;AACtD;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU;AAC3B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;AACjD,KAAK,EAAE;AACP,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACpC,QAAQ,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;AAC1C,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO;AACxB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;AACjD,KAAK,EAAE;AACP,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAClD,QAAQ,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AACvC,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;AAC3D,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ;AACzB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;AACjD,KAAK,EAAE;AACP,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAClC,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC;AACtE,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;AACjD,KAAK,EAAE;AACP,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC9B,QAAQ,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC1D,YAAY,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC3B,YAAY,UAAU,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE;AACzD,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;AACjD,KAAK,EAAE;AACP,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACvC,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC;AAC7B,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC;AACzF,QAAQ,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI;AAClF,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClG,YAAY,MAAM,CAAC,KAAK,CAAC;AACzB,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM;AACtD,QAAQ,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE;AAC/B,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,EAAE;AAC/C,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC;AACxE,YAAY,MAAM,CAAC,KAAK,CAAC;AACzB,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;AACjE,QAAQ,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC;AAC3D;AACA,QAAQ,GAAG,CAAC,OAAO,CAAC;AACpB,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC/B,YAAY,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AAC1B,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE;AACpE,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;AACjD,KAAK,EAAE;AACP,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACvC,QAAQ,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACjC,YAAY,MAAM,CAAC,KAAK,CAAC;AACzB,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;AACjF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;AAC9C,KAAK,EAAE;AACP,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AACpC,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AAC5B,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;AAC3C,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5C,gBAAgB,MAAM,CAAC,GAAG,CAAC;AAC3B,YAAY,EAAE;AACd,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,EAAE,YAAY,CAAC,GAAG,EAAE;AACnC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO;AAC5D,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,cAAc;AACvC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,EAAE;AACP,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACrC,QAAQ,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AAC/D,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;AAC9D,oBAAoB,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;AACvD,IAAI,KAAK;AACT;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC;AAC3D,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC;AACxD,KAAK,EAAE;AACP,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1C,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;AAC9B,QAAQ,GAAG,CAAC,CAAC;AACb,YAAY,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAC3E,YAAY,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC;AACpE,YAAY,MAAM,CAAC,UAAU,EAAE,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC7D,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrB,YAAY,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7B,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,SAAS,CAAC;AACzB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;AACvG,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AACzF,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,iBAAiB;AACzC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,EAAE;AACP,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACxC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;AACjC,YAAY,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,UAAU,EAAE,EAAE,GAAG;AAC5E,YAAY,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC;AAChE,YAAY,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,4BAA4B,CAAC,EAAE;AAC3E,oCAAoC,OAAO,CAAC,yBAAyB,CAAC,EAAE;AACxE,oCAAoC,OAAO,CAAC,wBAAwB,CAAC,EAAE;AACvE,oCAAoC,OAAO,CAAC,uBAAuB,CAAC,EAAE;AACtE,oCAAoC,OAAO,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC,CAAC;AACxE,YAAY,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC;AACrE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,QAAQ,CAAC;AACT,IAAI,KAAK;AACT;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;AACpB;AACA,GAAG;AACH,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,aAAa;AAC1E,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG;AACzE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO;AAC5E,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AACrE,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO;AACrE,CAAC,CAAC,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;AAC5E,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC;AAC9B,CAAC,CAAC;AACF,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,aAAa;AACjF,CAAC,CAAC,EAAE,OAAO,CAAC;AACZ,CAAC,EAAE;AACH,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM;AACvB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;AACjD,KAAK,EAAE;AACP,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC3B,QAAQ,GAAG,CAAC,OAAO,CAAC;AACpB,YAAY,IAAI,CAAC;AACjB,YAAY,GAAG,CAAC;AAChB,YAAY,IAAI,CAAC;AACjB,YAAY,WAAW,CAAC;AACxB,YAAY,KAAK,CAAC;AAClB,YAAY,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG;AAC3C,YAAY,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC;AACvC,YAAY,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC;AAC5B,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACxB;AACA,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS;AACvC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,YAAY,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,YAAY,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG;AAC3C,YAAY,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM;AAC9C,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClB,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;AACnF,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClF,YAAY,MAAM,CAAC,CAAC,CAAC,GAAG;AACxB,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM;AAC9D,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,YAAY,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1B,YAAY,EAAE,CAAC,CAAC;AAChB,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACnC,YAAY,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM;AACvD,YAAY,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;AACrC,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC9D,gBAAgB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM;AACzC,gBAAgB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACzC,oBAAoB,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE;AACzC,oBAAoB,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE;AAC3C;AACA,oBAAoB,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI;AAChD,oBAAoB,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC5C,wBAAwB,QAAQ,CAAC;AACjC,oBAAoB,CAAC;AACrB;AACA,oBAAoB,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM;AACvE,oBAAoB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvI,wBAAwB,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC5C,4BAA4B,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC;AAChD,4BAA4B,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;AACnF;AACA,wBAAwB,CAAC,CAAC,IAAI,CAAC,CAAC;AAChC,4BAA4B,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;AACzF,wBAAwB,CAAC;AACzB;AACA,wBAAwB,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI;AAClE,wBAAwB,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE;AACnF;AACA,oBAAoB,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM;AACtD,oBAAoB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACtD,wBAAwB,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9C,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM;AACrC,QAAQ,MAAM,CAAC,MAAM,CAAC;AACtB,IAAI,EAAE;AACN;AACA,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACnC,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;AAC5C,YAAY,MAAM,CAAC,KAAK,CAAC;AACzB,QAAQ,CAAC;AACT,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;AAC5C,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;AAC5C,YAAY,MAAM,CAAC,KAAK,CAAC;AACzB,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;AACpD,eAAe,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;AAClD,eAAe,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAChD,IAAI,EAAE;AACN;AACA,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG;AAC7C,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACpG,SAAS,CAAC,CAAC,CAAC,MAAM;AAClB,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,EAAE;AACX,QAAQ,gBAAgB,CAAC,CAAC,CAAC;AAC3B,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO;AACjC,YAAY,OAAO,CAAC,gBAAgB,IAAI,CAAC;AACzC,YAAY,WAAW,CAAC,YAAY,IAAI,CAAC;AACzC,YAAY,QAAQ,CAAC,eAAe,IAAI,CAAC;AACzC,YAAY,WAAW,CAAC,YAAY,CAAC,CAAC;AACtC,YAAY,iBAAiB,CAAC,MAAM,KAAK,CAAC;AAC1C,YAAY,mBAAmB,CAAC,IAAI,KAAK,CAAC;AAC1C,YAAY,iBAAiB,CAAC,MAAM,KAAK,CAAC;AAC1C,YAAY,WAAW,CAAC,YAAY,GAAG;AACvC;AACA,YAAY,EAAE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW;AACnD,YAAY,aAAa,CAAC,UAAU,IAAI,CAAC;AACzC,YAAY,WAAW,CAAC,YAAY,IAAI,CAAC;AACzC,YAAY,kBAAkB,CAAC,KAAK,KAAK,CAAC;AAC1C,YAAY,cAAc,CAAC,SAAS,KAAK,CAAC;AAC1C,YAAY,YAAY,CAAC,WAAW,KAAK,CAAC;AAC1C,YAAY,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK;AAC1F,YAAY,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI;AACzG,YAAY,gBAAgB,CAAC,OAAO,CAAC,CAAC;AACtC,YAAY,YAAY,CAAC,WAAW,IAAI,CAAC;AACzC,YAAY,YAAY,CAAC,WAAW,IAAI,CAAC;AACzC,YAAY,eAAe,CAAC,QAAQ,KAAK,CAAC;AAC1C;AACA,YAAY,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI;AACxC,YAAY,kBAAkB,CAAC,KAAK,GAAG,CAAC;AACxC,YAAY,kBAAkB,CAAC,KAAK,CAAC,CAAC;AACtC,YAAY,qBAAqB,CAAC,EAAE,GAAG,CAAC;AACxC,YAAY,qBAAqB,CAAC,EAAE,EAAE,CAAC;AACvC,YAAY,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACxC,YAAY,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACxC,YAAY,oBAAoB,CAAC,GAAG,CAAC;AACrC,gBAAgB,YAAY,CAAC,CAAC,IAAI,CAAC;AACnC,gBAAgB,WAAW,CAAC,CAAC,IAAI,CAAC;AAClC,gBAAgB,cAAc,CAAC,CAAC,KAAK,CAAC;AACtC,gBAAgB,WAAW,CAAC,CAAC,KAAK,CAAC;AACnC,gBAAgB,YAAY,CAAC,CAAC,KAAK,CAAC;AACpC,gBAAgB,aAAa,CAAC,CAAC,GAAG,CAAC;AACnC,gBAAgB,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACpC,gBAAgB,WAAW,CAAC,CAAC,KAAK;AAClC,YAAY,EAAE;AACd,YAAY,oBAAoB,CAAC,GAAG,CAAC;AACrC,gBAAgB,YAAY,CAAC,CAAC,KAAK,CAAC;AACpC,gBAAgB,WAAW,CAAC,CAAC,KAAK,CAAC;AACnC,gBAAgB,cAAc,CAAC,CAAC,IAAI,CAAC;AACrC,gBAAgB,WAAW,CAAC,CAAC,IAAI,CAAC;AAClC,gBAAgB,YAAY,CAAC,CAAC,IAAI,CAAC;AACnC,gBAAgB,aAAa,CAAC,CAAC,GAAG,CAAC;AACnC,gBAAgB,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACpC,gBAAgB,WAAW,CAAC,CAAC,KAAK;AAClC,YAAY,EAAE;AACd,YAAY,kBAAkB,CAAC,KAAK,CAAC;AACrC,gBAAgB,YAAY,CAAC,CAAC,KAAK,CAAC;AACpC,gBAAgB,WAAW,CAAC,CAAC,IAAI,CAAC;AAClC,gBAAgB,cAAc,CAAC,CAAC,KAAK,CAAC;AACtC,gBAAgB,WAAW,CAAC,CAAC,KAAK,CAAC;AACnC,gBAAgB,YAAY,CAAC,CAAC,KAAK,CAAC;AACpC,gBAAgB,aAAa,CAAC,CAAC,GAAG,CAAC;AACnC,gBAAgB,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACpC,gBAAgB,WAAW,CAAC,CAAC,KAAK;AAClC,YAAY,EAAE;AACd,YAAY,sBAAsB,CAAC,CAAC,CAAC;AACrC,gBAAgB,YAAY,CAAC,CAAC,KAAK,CAAC;AACpC,gBAAgB,WAAW,CAAC,CAAC,KAAK,CAAC;AACnC,gBAAgB,cAAc,CAAC,CAAC,IAAI,CAAC;AACrC,gBAAgB,WAAW,CAAC,CAAC,IAAI,CAAC;AAClC,gBAAgB,YAAY,CAAC,CAAC,IAAI,CAAC;AACnC,gBAAgB,aAAa,CAAC,CAAC,GAAG,CAAC;AACnC,gBAAgB,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACpC,gBAAgB,WAAW,CAAC,CAAC,KAAK;AAClC,YAAY,EAAE;AACd,YAAY,YAAY,CAAC,WAAW,CAAC,CAAC;AACtC,YAAY,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACxC,YAAY,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACxC,YAAY,SAAS,CAAC,cAAc,CAAC,CAAC;AACtC,YAAY,WAAW,CAAC,YAAY,KAAK,CAAC;AAC1C,YAAY,gBAAgB,CAAC,OAAO,IAAI,CAAC;AACzC,YAAY,eAAe,CAAC,QAAQ,KAAK,CAAC;AAC1C,YAAY,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ;AACrF,YAAY,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM;AACnF,YAAY,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,EAAE;AACvF,YAAY,SAAS,CAAC,cAAc,WAAW,GAAG;AAClD,YAAY,kBAAkB,CAAC,KAAK,EAAE,CAAC;AACvC,YAAY,UAAU,CAAC,aAAa,IAAI,CAAC;AACzC,YAAY,yBAAyB,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI;AACzE,YAAY,kBAAkB,CAAC,KAAK,EAAE,CAAC;AACvC;AACA,YAAY,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ;AACtC,YAAY,mBAAmB,CAAC,KAAK,IAAI,CAAC,EAAE,EAAE,QAAQ;AACtD,YAAY,qBAAqB,CAAC,GAAG,IAAI,CAAC,EAAE,EAAE,QAAQ;AACtD,YAAY,gBAAgB,CAAC,QAAQ,KAAK,CAAC,CAAC,EAAE,QAAQ;AACtD,YAAY,gBAAgB,CAAC,QAAQ,KAAK,CAAC,CAAC,EAAE,QAAQ;AACtD,YAAY,eAAe,CAAC,SAAS,KAAK,CAAC,CAAC,EAAE,QAAQ;AACtD,YAAY,qBAAqB,CAAC,GAAG,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ;AACrE,YAAY,uBAAuB,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ;AACrE,YAAY,eAAe,CAAC,SAAS,IAAI,CAAC,EAAE,EAAE,IAAI;AAClD,YAAY,eAAe,CAAC,SAAS,IAAI,CAAC,EAAE,EAAE,IAAI;AAClD,YAAY,mBAAmB,CAAC,KAAK,IAAI,CAAC,EAAE,EAAE,IAAI;AAClD,YAAY,mBAAmB,CAAC,KAAK,KAAK,CAAC,CAAC,EAAE,QAAQ;AACtD,YAAY,iBAAiB,CAAC,OAAO,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ;AACrE,YAAY,kBAAkB,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ;AACrE,YAAY,eAAe,CAAC,SAAS,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,aAAa;AACzE;AACA,YAAY,EAAE,QAAQ,CAAC,SAAS,CAAC,QAAQ;AACzC,YAAY,aAAa,CAAC,cAAc,KAAK,CAAC;AAC9C,YAAY,WAAW,CAAC,gBAAgB,IAAI,CAAC;AAC7C,YAAY,iBAAiB,CAAC,UAAU,IAAI,CAAC;AAC7C,YAAY,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC5C,YAAY,0BAA0B,CAAC,CAAC,KAAK,CAAC;AAC9C,YAAY,YAAY,CAAC,eAAe,IAAI,CAAC;AAC7C,YAAY,aAAa,CAAC,cAAc,IAAI,CAAC;AAC7C,YAAY,eAAe,CAAC,YAAY,IAAI,CAAC;AAC7C,YAAY,cAAc,CAAC,aAAa,IAAI,CAAC;AAC7C,YAAY,mBAAmB,CAAC,QAAQ,IAAI,CAAC;AAC7C,YAAY,iBAAiB,CAAC,UAAU,IAAI,CAAC;AAC7C,YAAY,eAAe,CAAC,YAAY,IAAI,CAAC;AAC7C;AACA,YAAY,EAAE,CAAC,OAAO,CAAC,QAAQ;AAC/B,YAAY,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAC1C;AACA,YAAY,EAAE,CAAC,UAAU;AACzB,YAAY,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAC1C,YAAY,OAAO,CAAC,oBAAoB,KAAK,CAAC;AAC9C,YAAY,kBAAkB,CAAC,SAAS,IAAI,CAAC;AAC7C,YAAY,oBAAoB,CAAC,OAAO,IAAI,CAAC;AAC7C;AACA,YAAY,EAAE,SAAS,CAAC,KAAK,CAAC,QAAQ;AACtC,YAAY,kBAAkB,CAAC,UAAU,KAAK,CAAC;AAC/C,YAAY,oBAAoB,CAAC,OAAO,CAAC,UAAU,EAAE;AACrD,YAAY,qBAAqB,CAAC,OAAO,IAAI,CAAC;AAC9C,YAAY,oBAAoB,CAAC,QAAQ,IAAI,CAAC;AAC9C,YAAY,mBAAmB,CAAC,SAAS,IAAI,CAAC;AAC9C,YAAY,sBAAsB,CAAC,MAAM,CAAC,WAAW,EAAE;AACvD,YAAY,uBAAuB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7C;AACA,YAAY,EAAE,UAAU,CAAC,aAAa,CAAC,QAAQ;AAC/C,YAAY,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM;AACvE,YAAY,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM;AAC9F,YAAY,gBAAgB,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,EAAE,QAAQ;AAC5D,YAAY,cAAc,CAAC,SAAS,KAAK,CAAC;AAC1C,YAAY,kBAAkB,CAAC,KAAK,GAAG,CAAC;AACxC,YAAY,oBAAoB,CAAC,GAAG,EAAE,CAAC;AACvC;AACA,YAAY,EAAE,WAAW,CAAC,QAAQ;AAClC,YAAY,gBAAgB,CAAC,OAAO,CAAC,CAAC;AACtC,YAAY,kBAAkB,CAAC,KAAK,GAAG,CAAC;AACxC,YAAY,OAAO,CAAC,gBAAgB,KAAK,CAAC;AAC1C,YAAY,SAAS,CAAC,cAAc,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS;AACzF;AACA,YAAY,EAAE,SAAS,CAAC,QAAQ,CAAC,QAAQ;AACzC,YAAY,SAAS,CAAC,cAAc,EAAE,MAAM,GAAG;AAC/C,YAAY,SAAS,CAAC,CAAC,CAAC;AACxB,gBAAgB,MAAM,CAAC,CAAC,CAAC;AACzB,oBAAoB,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE;AAC9C,oBAAoB,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAAC,GAAG,EAAE;AACpD,oBAAoB,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE;AAC/C,oBAAoB,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC;AAChD,gBAAgB,EAAE;AAClB,gBAAgB,OAAO,CAAC,CAAC,CAAC;AAC1B,oBAAoB,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,EAAE;AAC/C,oBAAoB,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE;AACrD,oBAAoB,KAAK,CAAC,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE;AAChD,oBAAoB,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC;AACjD,gBAAgB,EAAE;AAClB,gBAAgB,IAAI,CAAC,CAAC,CAAC;AACvB,oBAAoB,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;AAC5C,oBAAoB,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,EAAE;AAClD,oBAAoB,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE;AAC7C,oBAAoB,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC;AAC9C,gBAAgB,EAAE;AAClB,gBAAgB,QAAQ,CAAC,CAAC,CAAC;AAC3B,oBAAoB,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,EAAE;AAChD,oBAAoB,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAAC,GAAG,EAAE;AACtD,oBAAoB,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE;AACjD,oBAAoB,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC;AAClD,gBAAgB,EAAE;AAClB,gBAAgB,UAAU,CAAC,CAAC,CAAC;AAC7B,oBAAoB,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,EAAE;AAClD,oBAAoB,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAAC,GAAG,EAAE;AACxD,oBAAoB,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAAC,GAAG,EAAE;AACnD,oBAAoB,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC;AACpD,gBAAgB,EAAE;AAClB,gBAAgB,WAAW,CAAC,CAAC,CAAC;AAC9B,oBAAoB,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,GAAG,EAAE;AACnD,oBAAoB,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAAC,GAAG,EAAE;AACzD,oBAAoB,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAAC,GAAG,EAAE;AACpD,oBAAoB,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAAC,GAAG,CAAC;AACrD,gBAAgB,EAAE;AAClB,gBAAgB,QAAQ,CAAC,CAAC,CAAC;AAC3B,oBAAoB,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,EAAE;AAChD,oBAAoB,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAAC,GAAG,EAAE;AACtD,oBAAoB,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE;AACjD,oBAAoB,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC;AAClD,gBAAgB,EAAE;AAClB,gBAAgB,IAAI,CAAC,CAAC,CAAC;AACvB,oBAAoB,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;AAC5C,oBAAoB,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,EAAE;AAClD,oBAAoB,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE;AAC7C,oBAAoB,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC;AAC9C,gBAAgB,CAAC;AACjB,YAAY,EAAE;AACd;AACA,YAAY,EAAE,SAAS,CAAC,QAAQ;AAChC,YAAY,SAAS,CAAC,cAAc,KAAK,CAAC;AAC1C,YAAY,cAAc,CAAC,SAAS,GAAG,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE;AACvI,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK;AAC/E,SAAS,CAAC,OAAO,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,MAAM;AAClB,SAAS,CAAC,CAAC,CAAC,MAAM;AAClB,SAAS,EAAE;AACX,QAAQ,MAAM,CAAC,CAAC,KAAK,SAAS,MAAM;AACpC;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AACtG,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AACjC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM;AACnC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC;AAC9B,SAAS,EAAE;AACX,QAAQ,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC9C,YAAY,MAAM,CAAC,QAAQ,GAAG;AAC9B,gBAAgB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACrC,gBAAgB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;AAC1C,oBAAoB,IAAI,CAAC,CAAC,CAAC,GAAG;AAC9B,gBAAgB,CAAC;AACjB,gBAAgB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE;AACpD,YAAY,EAAE;AACd,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;AAC7C,SAAS,CAAC,CAAC,CAAC,MAAM;AAClB,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AACrC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AAChC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AACrC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AACpC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AACpC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AACnC,SAAS,EAAE;AACX,QAAQ,QAAQ,CAAC,CAAC,CAAC;AACnB,YAAY,OAAO,CAAC,IAAI,CAAC,CAAC;AAC1B,YAAY,EAAE,CAAC,SAAS,CAAC,CAAC;AAC1B,YAAY,OAAO,CAAC,IAAI,CAAC,CAAC;AAC1B,YAAY,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1B,YAAY,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1B,YAAY,KAAK,CAAC,MAAM,CAAC;AACzB,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC;AAC7D,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC;AACpE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;AACzF,SAAS,EAAE;AACX,QAAQ,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACzC,YAAY,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,gBAAgB,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,EAAE;AAC7D,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,OAAO,CAAC;AAC3B,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AAC3E,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;AACnF,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AACjG,SAAS,EAAE;AACX,QAAQ,kBAAkB,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACjD,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG;AACvC,gBAAgB,OAAO,CAAC;AACxB,gBAAgB,YAAY,CAAC;AAC7B;AACA,YAAY,OAAO,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AACnD,YAAY,OAAO,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE;AAC5E,YAAY,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE;AAC/D;AACA,YAAY,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACpC;AACA,gBAAgB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC;AAC/C,gBAAgB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC;AAC9C;AACA,gBAAgB,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAChC,oBAAoB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE;AAC9D,gBAAgB,CAAC;AACjB;AACA,gBAAgB,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC;AACvC,gBAAgB,OAAO,CAAC,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE;AAC3E,gBAAgB,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE;AACnE,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,MAAM,CAAC;AAC1B,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;AAC3H,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;AAClF,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;AACjJ,SAAS,EAAE;AACX,QAAQ,gBAAgB,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC/C,YAAY,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AAC9C;AACA,YAAY,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;AACvD,gBAAgB,UAAU,CAAC;AAC3B,gBAAgB,GAAG,CAAC;AACpB,gBAAgB,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;AACnD;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACzB,gBAAgB,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG;AACrC,YAAY,CAAC;AACb;AACA,YAAY,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC;AAC7C;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,qBAAqB,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC9E,gBAAgB,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,qBAAqB,GAAG;AAC/D,YAAY,CAAC;AACb;AACA,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACzC,gBAAgB,GAAG,CAAC,CAAC;AACrB,gBAAgB,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxC,oBAAoB,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;AACzD,oBAAoB,KAAK,CAAC;AAC1B;AACA,YAAY,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AAC/B,gBAAgB,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AAClH,gBAAgB,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9G,YAAY,EAAE;AACd,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;AAChE,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO;AAC1C,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACzC,SAAS,EAAE;AACX,QAAQ,cAAc,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC7C,YAAY,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AAC9C;AACA,YAAY,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AAC/B,gBAAgB,OAAO,CAAC,WAAW,CAAC;AACpC,gBAAgB,OAAO,CAAC,YAAY;AACpC,YAAY,EAAE;AACd,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;AAC7D,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO;AAC1C,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC;AAC9B,SAAS,EAAE;AACX,QAAQ,eAAe,CAAC;AACxB,YAAY,QAAQ,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;AACnD,YAAY,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACjC,gBAAgB,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AAClD,gBAAgB,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC;AAC5C,YAAY,CAAC,CAAC,CAAC;AACf,YAAY,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACjC,gBAAgB,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AAClD,gBAAgB,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE;AAC9D,YAAY,EAAE;AACd;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC;AACxE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI;AACrD,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG;AAChF,SAAS,CAAC,CAAC,SAAS,CAAC;AACrB,SAAS,EAAE;AACX,QAAQ,8BAA8B,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC5D,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG;AAC1B;AACA,YAAY,EAAE,8BAA8B,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AACnE,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AACnD,oBAAoB,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE;AAC1C,gBAAgB,CAAC;AACjB,gBAAgB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,EAAE,GAAG,GAAG,KAAK,CAAC;AAChE,gBAAgB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAClC,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AACpD,oBAAoB,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AACtC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,oBAAoB,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE;AAC/D,wBAAwB,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG;AACpD,oBAAoB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,qBAAqB,CAAC,QAAQ,EAAE;AACnE,oBAAoB,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC/D,wBAAwB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AACxD,wBAAwB,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AACxD,4BAA4B,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1C,4BAA4B,KAAK,CAAC;AAClC,wBAAwB,CAAC;AACzB,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB,gBAAgB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AACxC,gBAAgB,MAAM,CAAC,MAAM,CAAC;AAC9B,YAAY,EAAE;AACd,YAAY,MAAM,CAAC,EAAE,8BAA8B,CAAC,QAAQ,EAAE;AAC9D,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM;AACnD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AACjC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW;AACzE,SAAS,EAAE;AACX,QAAQ,qBAAqB,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AACjD,YAAY,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE;AACpE,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM;AACzE,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;AAC5B,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACtE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM;AAC5C,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM;AAC/D,SAAS,EAAE;AACX,QAAQ,cAAc,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAClD,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;AACzC,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,gBAAgB,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC;AACjC,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,MAAM,CAAC;AAC1B,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE;AAClG,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AAC7C,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;AAC7B,SAAS,EAAE;AACX,QAAQ,cAAc,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpD,YAAY,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AAC9C,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,OAAO,CAAC,EAAE;AACvD,gBAAgB,IAAI,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,OAAO,CAAC,EAAE;AACnD,YAAY,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AAC5H,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG;AACzE,SAAS,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AACjC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AAC3B,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI;AAC5C,SAAS,CAAC,CAAC,CAAC,OAAO;AACnB,SAAS,EAAE;AACX,QAAQ,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACrC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE;AACxB,gBAAgB,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,oBAAoB,MAAM,CAAC,KAAK,CAAC;AACjC,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACzC,oBAAoB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;AACxC,gBAAgB,EAAE;AAClB,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACvC,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC1E,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AACjC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACzC,SAAS,EAAE;AACX,QAAQ,gBAAgB,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7C;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACtD,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACvD,oBAAoB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG;AAC/C;AACA,oBAAoB,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AAChD,oBAAoB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3C,oBAAoB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3C;AACA,oBAAoB,MAAM,CAAC,MAAM,CAAC;AAClC,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/D,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACvD,oBAAoB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG;AAC/C;AACA,oBAAoB,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AAChD,oBAAoB,MAAM,CAAC,CAAC,CAAC,CAAC;AAC9B,wBAAwB,KAAK,CAAC,OAAO,CAAC,CAAC;AACvC,wBAAwB,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AAClD,wBAAwB,QAAQ,CAAC,eAAe,CAAC,UAAU,CAAC;AAC5D,oBAAoB,MAAM,CAAC,CAAC,CAAC,CAAC;AAC9B,wBAAwB,KAAK,CAAC,OAAO,CAAC,CAAC;AACvC,wBAAwB,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AACjD,wBAAwB,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC;AAC3D;AACA,oBAAoB,MAAM,CAAC,MAAM,CAAC;AAClC,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;AAChC,oBAAoB,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE;AACvE,gBAAgB,EAAE;AAClB,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,EAAE,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE;AAC/C,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;AACzD,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACzC,SAAS,EAAE;AACX,QAAQ,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACnC,YAAY,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,GAAG;AAC7D,gBAAgB,IAAI,QAAQ,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG;AAClD;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,gBAAgB,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,GAAG;AAC7C,oBAAoB,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AACvC,wBAAwB,MAAM,CAAC,WAAW,CAAC;AAC3C,wBAAwB,MAAM,CAAC,WAAW;AAC1C,oBAAoB,EAAE;AACtB,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC7D,gBAAgB,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,GAAG;AAC7C,oBAAoB,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AACvC,wBAAwB,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC;AACjD,wBAAwB,QAAQ,CAAC,IAAI,CAAC,SAAS;AAC/C,oBAAoB,EAAE;AACtB,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACzE,gBAAgB,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,GAAG;AAC7C,oBAAoB,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AACvC,wBAAwB,QAAQ,CAAC,eAAe,CAAC,UAAU,CAAC;AAC5D,wBAAwB,QAAQ,CAAC,eAAe,CAAC,SAAS;AAC1D,oBAAoB,EAAE;AACtB,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC;AAC9E,gBAAgB,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACzC,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,EAAE,aAAa,GAAG;AACrC,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;AACxC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACzC,SAAS,EAAE;AACX,QAAQ,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC3C,YAAY,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/D,gBAAgB,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACtD,oBAAoB,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AAC1D,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,aAAa,GAAG;AACvD,gBAAgB,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACrD,oBAAoB,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,oBAAoB,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK;AACpE,oBAAoB,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9D,oBAAoB,MAAM,CAAC;AAC3B,gBAAgB,CAAC;AACjB;AACA,gBAAgB,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACpD,gBAAgB,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACnD,gBAAgB,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,GAAG;AACtD,gBAAgB,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE;AAC5D,oBAAoB,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5D,oBAAoB,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC1D,wBAAwB,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC5D,wBAAwB,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC3D,oBAAoB,EAAE;AACtB,oBAAoB,MAAM,CAAC;AAC3B,gBAAgB,CAAC;AACjB;AACA,gBAAgB,QAAQ,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC/D,gBAAgB,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC9D,gBAAgB,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,GAAG;AAClD,gBAAgB,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE;AAC5D,oBAAoB,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5D,oBAAoB,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC1D,wBAAwB,QAAQ,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACvE,wBAAwB,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACtE,oBAAoB,EAAE;AACtB,oBAAoB,MAAM,CAAC;AAC3B,gBAAgB,CAAC;AACjB;AACA,gBAAgB,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC;AACpE,gBAAgB,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACtD,gBAAgB,EAAE;AAClB,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC,MAAM,CAAC,EAAE;AAC7C,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;AACtD,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACzC,SAAS,EAAE;AACX,QAAQ,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACnC,YAAY,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,GAAG;AAC5D,gBAAgB,IAAI,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG;AAC9C;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5D,gBAAgB,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,GAAG;AAC7C,oBAAoB,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AACvC,wBAAwB,MAAM,CAAC,UAAU,CAAC;AAC1C,wBAAwB,MAAM,CAAC,WAAW;AAC1C,oBAAoB,EAAE;AACtB,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AAC7E,gBAAgB,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,GAAG;AAC7C,oBAAoB,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AACvC,wBAAwB,QAAQ,CAAC,eAAe,CAAC,WAAW,CAAC;AAC7D,wBAAwB,QAAQ,CAAC,eAAe,CAAC,YAAY;AAC7D,oBAAoB,EAAE;AACtB,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACjE,gBAAgB,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,GAAG;AAC7C,oBAAoB,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AACvC,wBAAwB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC;AAClD,wBAAwB,QAAQ,CAAC,IAAI,CAAC,YAAY;AAClD,oBAAoB,EAAE;AACtB,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,IAAI;AAC5E,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,EAAE,aAAa,GAAG;AACrC,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AAC5E,SAAS,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM;AAC9C,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO;AAC1C,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO;AACvD,SAAS,EAAE;AACX,QAAQ,gBAAgB,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC/C,YAAY,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AAC7D,YAAY,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AAC9C;AACA,YAAY,EAAE;AACd,gBAAgB,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM;AACtG,gBAAgB,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;AAC1C,aAAa,EAAE;AACf;AACA,YAAY,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC5B,gBAAgB,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAC9C,gBAAgB,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAC9C,gBAAgB,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7C,YAAY,EAAE;AACd;AACA,YAAY,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAAC;AACzF,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AACzC,gBAAgB,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE;AACjC,gBAAgB,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG;AAC/B,gBAAgB,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE;AAC7B,YAAY,GAAG;AACf;AACA,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AACzC,gBAAgB,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;AACpC,YAAY,GAAG;AACf;AACA,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AACzC,gBAAgB,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE;AACtC,gBAAgB,aAAa,CAAC,CAAC,CAAC,MAAM,EAAE;AACxC,gBAAgB,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;AACnC,YAAY,GAAG;AACf;AACA,YAAY,QAAQ,CAAC,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG;AACjD,YAAY,QAAQ,CAAC,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG;AACjD,YAAY,QAAQ,CAAC,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE;AAC7C;AACA,YAAY,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE;AAC/B,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ;AACjF,SAAS,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAClC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;AAC7B,SAAS,EAAE;AACX,QAAQ,kBAAkB,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACjD,YAAY,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,EAAE;AAC5D,gBAAgB,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AACxC;AACA,YAAY,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE;AAClD,YAAY,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;AACtC,YAAY,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE;AACrC,YAAY,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE;AACrC,YAAY,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE;AACxC;AACA,YAAY,MAAM,CAAC,OAAO,CAAC;AAC3B,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,SAAS;AAC1E,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,EAAE;AACX,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1B,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3B,gBAAgB,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AACjC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACpC,oBAAoB,MAAM,CAAC,GAAG,CAAC,IAAI,GAAG,OAAO,GAAG;AAChD,gBAAgB,EAAE;AAClB,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,EAAE,GAAG,GAAG;AAC3B,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC;AAC9E,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI;AAC7E,SAAS,CAAC,CAAC,GAAG,CAAC;AACf,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG;AAC9B,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;AAC7B,SAAS,EAAE;AACX,QAAQ,oBAAoB,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC/C;AACA,YAAY,EAAE,oBAAoB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE;AACrD,gBAAgB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AACxD;AACA,gBAAgB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AAC9B;AACA,gBAAgB,MAAM,CAAC,GAAG,CAAC;AAC3B,YAAY,EAAE;AACd;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/E;AACA,gBAAgB,EAAE,oBAAoB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE;AACzD,oBAAoB,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAChE,wBAAwB,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACvC;AACA,oBAAoB,OAAO,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,IAAI,GAAG;AAC3D,oBAAoB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE;AAC3D;AACA,oBAAoB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC7C,wBAAwB,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACvF,wBAAwB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACzF;AACA,wBAAwB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1C,wBAAwB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACxE,oBAAoB,EAAE;AACtB;AACA,oBAAoB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AAClC,oBAAoB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAC1C,wBAAwB,CAAC,MAAM,CAAC,gBAAgB,CAAC,SAAS,CAAC,gBAAgB,CAAC,GAAG,GAAG,CAAC,CAAC;AACpF,wBAAwB,GAAG,CAAC,CAAC;AAC7B,wBAAwB,GAAG,CAAC,YAAY,EAAE,KAAK,IAAI;AACnD;AACA,oBAAoB,MAAM,CAAC,OAAO,CAAC;AACnC,gBAAgB,EAAE;AAClB;AACA,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,EAAE,oBAAoB,CAAC,CAAC,GAAG,CAAC,EAAE;AACjD,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC;AACrD,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAClC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AACvC,SAAS,EAAE;AACX,QAAQ,iBAAiB,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACpE;AACA,YAAY,GAAG,CAAC,SAAS,CAAC;AAC1B,gBAAgB,QAAQ,CAAC;AACzB;AACA,YAAY,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AAC9C;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClD,gBAAgB,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE;AAChD,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACtC,gBAAgB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;AACnE,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,oBAAoB,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE;AAC5D,oBAAoB,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI;AACnE,oBAAoB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AACpD,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,oBAAoB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG;AAC9C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE;AAC/E,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO;AAC1C,SAAS,EAAE;AACX,QAAQ,yBAAyB,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACxD,YAAY,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AAC9C,YAAY,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,gBAAgB,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AACnD,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9E,gBAAgB,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AACrD,YAAY,CAAC;AACb,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AACrE,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS;AACpC,SAAS,EAAE;AACX,QAAQ,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAClD,YAAY,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AAC9C;AACA,YAAY,EAAE,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;AACrC,gBAAgB,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9C,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC1D,gBAAgB,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3D,gBAAgB,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACrD,YAAY,CAAC;AACb,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;AAC9E,SAAS,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AAC1B,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI;AACtC,SAAS,CAAC,CAAC,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa;AACvH,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO;AACxE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI;AAC5D,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AACnE,SAAS,EAAE;AACX,QAAQ,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC9D,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC5C,gBAAgB,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC5E,oBAAoB,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,SAAS,CAAC,EAAE;AACrE,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC5E,oBAAoB,GAAG,CAAC,CAAC,CAAC;AAC1B,wBAAwB,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D,wBAAwB,MAAM,CAAC;AAC/B,oBAAoB,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,wBAAwB,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE;AAC/C,oBAAoB,CAAC;AACrB;AACA,oBAAoB,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,oBAAoB,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5D,wBAAwB,MAAM,CAAC,CAAC,CAAC,CAAC;AAClC,oBAAoB,CAAC;AACrB;AACA,oBAAoB,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtC,wBAAwB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3D,oBAAoB,CAAC;AACrB;AACA,oBAAoB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACxD,wBAAwB,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AAC3D,4BAA4B,MAAM,CAAC,CAAC,CAAC;AACrC,wBAAwB,CAAC;AACzB,oBAAoB,CAAC;AACrB,oBAAoB,MAAM,CAAC,CAAC,CAAC,CAAC;AAC9B,gBAAgB,EAAE;AAClB,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,CAAC,SAAS,CAAC,EAAE;AACnE,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;AAC3D,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS;AACpC,SAAS,EAAE;AACX,QAAQ,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACrD,YAAY,GAAG,CAAC,UAAU,CAAC;AAC3B,gBAAgB,UAAU,CAAC,CAAC,CAAC,GAAG;AAChC,gBAAgB,CAAC,CAAC;AAClB;AACA,YAAY,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AAC9C,YAAY,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAC1D,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACvD,gBAAgB,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACzE,oBAAoB,UAAU,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACvD,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,YAAY,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,GAAG;AACrD,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC;AAC/E,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS;AACpC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO;AACpC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;AACxC,SAAS,EAAE;AACX,QAAQ,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAChC,YAAY,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAC5C,gBAAgB,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC7E,oBAAoB,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AACtD,oBAAoB,OAAO,CAAC,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,EAAE;AAC/E,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC9C,gBAAgB,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC7E,oBAAoB,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AACtD,oBAAoB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE;AACrE,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE;AAC3D,YAAY,CAAC;AACb,QAAQ,KAAK;AACb;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG;AAC9E,SAAS,CAAC,CAAC,OAAO,CAAC;AACnB,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS;AACpC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO;AACpC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;AACxC,SAAS,EAAE;AACX,QAAQ,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACnC,YAAY,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;AAC/C,gBAAgB,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC7E,oBAAoB,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AACtD,oBAAoB,OAAO,CAAC,mBAAmB,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,EAAE;AAClF,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC9C,gBAAgB,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC5E,oBAAoB,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AACtD,oBAAoB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE;AACrE,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE;AAC3D,YAAY,CAAC;AACb,QAAQ,KAAK;AACb;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG;AAC5E,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;AACnD,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AACjC,SAAS,EAAE;AACX,QAAQ,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxC,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACxC;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AACzC,gBAAgB,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AAClD,oBAAoB,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO;AACjD,oBAAoB,KAAK,CAAC,cAAc,GAAG;AAC3C,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AAClD,oBAAoB,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AAChD,oBAAoB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO;AACpD,oBAAoB,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACxC,oBAAoB,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO;AAChD,oBAAoB,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC;AAC9C,gBAAgB,EAAE;AAClB,YAAY,CAAC;AACb,YAAY,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACnC,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;AACzD,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AACjC,SAAS,EAAE;AACX,QAAQ,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACtC,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACxC;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAC1C,gBAAgB,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW;AAC/C,gBAAgB,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AAChD,oBAAoB,KAAK,CAAC,eAAe,GAAG;AAC5C,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW;AAC9C,gBAAgB,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AAChD,oBAAoB,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AAChD,oBAAoB,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9C,gBAAgB,EAAE;AAClB;AACA,YAAY,CAAC;AACb;AACA,YAAY,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE;AACjC,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI;AAC9E,SAAS,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM;AAC7E,SAAS,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS;AAChF,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI;AAC3E,SAAS,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC;AAChF,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AACjC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM;AACnC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG;AAChF,SAAS,CAAC,EAAE,OAAO,CAAC,QAAQ;AAC5B,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC;AAC9B,SAAS,EAAE;AACX,QAAQ,cAAc,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACpD,YAAY,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO;AAChF,YAAY,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AAC7E,YAAY,EAAE,MAAM,OAAO,CAAC;AAC5B,YAAY,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG;AACjC,gBAAgB,CAAC,CAAC;AAClB,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACtD,gBAAgB,WAAW,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACnD,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC/B,gBAAgB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE;AACpD,oBAAoB,CAAC,CAAC;AACtB,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC1D,oBAAoB,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAChD,gBAAgB,CAAC;AACjB;AACA,gBAAgB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE;AACpD,YAAY,EAAE;AACd,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;AAClF,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG;AAC9B,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC;AACxF,SAAS,EAAE;AACX,QAAQ,eAAe,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC1C,YAAY,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM;AAC5D,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,EAAE;AACzC,YAAY,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACxC,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ;AACjF,SAAS,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC;AACvB,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,OAAO;AACnB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;AACrE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI;AACzE,SAAS,EAAE;AACX,QAAQ,cAAc,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACzC,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE;AACrD,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACnC,gBAAgB,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ;AAC1E,gBAAgB,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;AAChD,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,GAAG;AAC1C,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AAC/B,SAAS,CAAC,CAAC,CAAC,OAAO;AACnB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ;AAC/E,SAAS,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE;AAC3E,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC;AACpC,SAAS,EAAE;AACX,QAAQ,iBAAiB,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9C,YAAY,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;AAC3E,YAAY,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC;AACpD,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI;AACzF,YAAY,GAAG,CAAC,cAAc,CAAC;AAC/B,YAAY,GAAG,CAAC,CAAC;AACjB,gBAAgB,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE;AAC/C,gBAAgB,cAAc,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,EAAE;AAC5E,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1B,gBAAgB,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC;AACvC,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AACnC,gBAAgB,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AAC9C,oBAAoB,EAAE,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7D,wBAAwB,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACtC,4BAA4B,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,EAAE;AAC5E,wBAAwB,CAAC;AACzB,wBAAwB,MAAM,CAAC,GAAG,CAAC,cAAc,GAAG;AACpD,oBAAoB,EAAE;AACtB,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,oBAAoB,EAAE,iBAAiB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACtD,wBAAwB,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,EAAE;AACxE,oBAAoB,EAAE;AACtB,gBAAgB,CAAC;AACjB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AACjD,gBAAgB,EAAE,iBAAiB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAClD,oBAAoB,MAAM,CAAC,GAAG,CAAC,cAAc,GAAG;AAChD,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,EAAE;AAC7E,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,EAAE,iBAAiB,CAAC,CAAC,KAAK,CAAC,EAAE;AAChD,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;AACjC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAClC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO;AAC3D,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ;AAC1F,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM;AACvF,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO;AAC/E,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO;AAC3F,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,eAAe;AACtG,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;AAC1B,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC;AACpC,SAAS,EAAE;AACX,QAAQ,eAAe,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC9D,YAAY,GAAG,CAAC,eAAe,CAAC;AAChC,YAAY,GAAG,CAAC,OAAO,CAAC;AACxB,YAAY,GAAG,CAAC,YAAY,CAAC;AAC7B;AACA,YAAY,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK;AACzF,YAAY,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;AAChD,YAAY,EAAE,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AACzC,gBAAgB,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AACxC,gBAAgB,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;AACpC,gBAAgB,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC;AACtD,gBAAgB,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AACtC,gBAAgB,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC;AACxD,gBAAgB,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;AAC9B,YAAY,CAAC;AACb;AACA,YAAY,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,GAAG,CAAC,EAAE;AACnD,YAAY,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE;AACtE;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C,gBAAgB,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE;AACjF,YAAY,CAAC;AACb;AACA,YAAY,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACrD,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,UAAU,CAAC;AACxG,gBAAgB,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,oBAAoB,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,KAAK;AAC9D;AACA,oBAAoB,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE;AAC9F,oBAAoB,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ;AACnE,oBAAoB,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAC3E,wBAAwB,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AACjD,0BAA0B,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE;AACjD,0BAA0B,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;AACpD,wBAAwB,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE;AAC7C,oBAAoB,CAAC,CAAC,IAAI,CAAC,CAAC;AAC5B,wBAAwB,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE;AAC7F;AACA,wBAAwB,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,4BAA4B,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE;AAC/C,wBAAwB,CAAC;AACzB,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB,YAAY,EAAE;AACd;AACA,YAAY,GAAG,CAAC,CAAC;AACjB,gBAAgB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE;AACjD;AACA,gBAAgB,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;AACnC,oBAAoB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC;AACxD,gBAAgB,CAAC;AACjB;AACA,gBAAgB,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC9B,oBAAoB,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;AACrD,wBAAwB,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;AACxF,4BAA4B,OAAO,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,UAAU,GAAG;AACtF,wBAAwB,CAAC;AACzB,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB;AACA,gBAAgB,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;AACtC,oBAAoB,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC;AACnD,gBAAgB,CAAC;AACjB;AACA,gBAAgB,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE;AACnC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzB,gBAAgB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;AACpC;AACA,gBAAgB,EAAE;AAClB,oBAAoB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI;AAC5G,oBAAoB,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AAC3G,oBAAoB,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC7G,oBAAoB,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI;AACxG,oBAAoB,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;AAC5E;AACA,oBAAoB,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO;AACzG,oBAAoB,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AACzG,oBAAoB,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC;AACjD,gBAAgB,EAAE;AAClB,gBAAgB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;AACxF,gBAAgB,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC9F,oBAAoB,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE;AAC1G,gBAAgB,CAAC;AACjB;AACA,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE;AACjF;AACA,gBAAgB,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,KAAK;AAC1D;AACA,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,cAAc;AAClG,oBAAoB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,GAAG;AACnD,oBAAoB,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC9B,wBAAwB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,4BAA4B,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D,gCAAgC,SAAS,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AACnE,oCAAoC,YAAY,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;AACnE,oCAAoC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE;AACxH,oCAAoC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;AACpD,gCAAgC,GAAG;AACnC,4BAA4B,CAAC;AAC7B,wBAAwB,EAAE;AAC1B,wBAAwB,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,4BAA4B,EAAE,CAAC,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;AACxD,gCAAgC,OAAO,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AACjE,oCAAoC,YAAY,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;AACnE,oCAAoC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ;AACnE,oCAAoC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE;AACnL,gCAAgC,GAAG;AACnC,4BAA4B,CAAC;AAC7B,wBAAwB,EAAE;AAC1B,wBAAwB,GAAG,CAAC,CAAC;AAC7B,4BAA4B,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE;AACjD,4BAA4B,GAAG,CAAC,IAAI,GAAG;AACvC,wBAAwB,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACtC,4BAA4B,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5D,gCAAgC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;AACtD,4BAA4B,CAAC;AAC7B,wBAAwB,CAAC;AACzB,oBAAoB,CAAC;AACrB,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,oBAAoB,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,wBAAwB,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9C,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,OAAO,CAAC;AAC3B,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAClC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG;AACtC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,QAAQ;AAC7C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS;AACnF,SAAS,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;AACnD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;AAC9E,SAAS,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;AAChD,SAAS,EAAE;AACX,QAAQ,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE;AACnC,YAAY,GAAG,CAAC,MAAM,CAAC;AACvB,gBAAgB,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;AACtC,gBAAgB,IAAI,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AAC1C,oBAAoB,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACnE,oBAAoB,QAAQ,CAAC,eAAe,CAAC;AAC7C,gBAAgB,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AAClF,gBAAgB,QAAQ,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,EAAE;AACxD,gBAAgB,OAAO,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;AAC5D,gBAAgB,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;AAC5D,gBAAgB,QAAQ,MAAM,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;AACjD;AACA,YAAY,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE;AAC9D,YAAY,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ;AACpC,YAAY,GAAG,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC;AACxF;AACA,YAAY,EAAE,CAAC,OAAO,CAAC,QAAQ;AAC/B,YAAY,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC5D,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE;AACjC,oBAAoB,GAAG,CAAC;AACxB,wBAAwB,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,EAAE;AACvD,oBAAoB,CAAC,KAAK,CAAC,CAAC,EAAE;AAC9B,wBAAwB,EAAE,OAAO;AACjC,oBAAoB,CAAC;AACrB,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,oBAAoB,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACvD,gBAAgB,CAAC;AACjB,gBAAgB,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;AAC3D,oBAAoB,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE;AACzC,gBAAgB,CAAC;AACjB,YAAY,EAAE;AACd;AACA,YAAY,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AACxD;AACA,YAAY,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ;AAC5D,YAAY,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AACzE,gBAAgB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;AACvC,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AAC1C,gBAAgB,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;AACvD,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AAC7B;AACA,YAAY,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ;AAC/C,YAAY,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAChF;AACA,gBAAgB,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrG;AACA,oBAAoB,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE;AAC/C,oBAAoB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC;AACrE;AACA,oBAAoB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM;AACxC,oBAAoB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACtD,wBAAwB,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,EAAE;AACnD,oBAAoB,CAAC;AACrB;AACA,oBAAoB,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM;AAC7C,oBAAoB,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACvC,gBAAgB,CAAC;AACjB,YAAY,EAAE;AACd,YAAY,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;AACjF,YAAY,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE;AACtE,YAAY,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;AACzD;AACA,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC;AACjD,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC;AAC5D,SAAS,EAAE;AACX,QAAQ,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACnC,YAAY,KAAK,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG;AAChF,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AACjC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC;AAC9B,SAAS,EAAE;AACX,QAAQ,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACtC,YAAY,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACrC;AACA,gBAAgB,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACjD,oBAAoB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACtC,wBAAwB,MAAM,CAAC;AAC/B;AACA,oBAAoB,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,GAAG;AAC7C,oBAAoB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE;AAC1E,oBAAoB,MAAM,CAAC,MAAM,CAAC;AAClC,gBAAgB,EAAE;AAClB;AACA,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AAChD;AACA,gBAAgB,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACjD,oBAAoB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACtC;AACA,oBAAoB,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE;AACrE,oBAAoB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AACzC,oBAAoB,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE;AAC7C,oBAAoB,MAAM,CAAC,MAAM,CAAC;AAClC,gBAAgB,EAAE;AAClB;AACA,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE;AACtE,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE;AACxC,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC;AACzD,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AACjC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;AAC5B,SAAS,EAAE;AACX,QAAQ,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AACrC,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACnD,gBAAgB,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AAChD,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI;AACnE,gBAAgB,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AAChD,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE;AACxC,oBAAoB,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI;AACtD,oBAAoB,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK;AACpD,gBAAgB,EAAE;AAClB,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE;AACvC,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI;AAC3E,SAAS,CAAC,CAAC,OAAO,CAAC;AACnB,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACtC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;AAC7B,SAAS,EAAE;AACX,QAAQ,oBAAoB,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACrD,YAAY,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG;AACnD,YAAY,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM;AAC5D,YAAY,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,EAAE;AAC5D,QAAQ,CAAC;AACT;AACA,IAAI,GAAG;AACP;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC;AAChG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAC/B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,CAAC,CAAC,CAAC,MAAM;AACd,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC;AAChH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AACjC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC;AACrF,KAAK,EAAE;AACP,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AACjB,QAAQ,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC;AACvC,QAAQ,OAAO,CAAC,IAAI,CAAC,CAAC;AACtB,QAAQ,KAAK,CAAC,MAAM,IAAI;AACxB,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACvB,YAAY,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC;AAC1B,YAAY,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC;AACzB,YAAY,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC;AACzB,YAAY,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC;AACzB,YAAY,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC;AAC1B,YAAY,CAAC,GAAG,EAAE,EAAE,KAAK;AACzB,QAAQ,EAAE;AACV,QAAQ,SAAS,CAAC,CAAC,CAAC,GAAG;AACvB;AACA,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;AACjB,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;AACzE,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC;AAC9C,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC;AACvC,YAAY,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;AACtC,YAAY,KAAK,CAAC;AAClB;AACA,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE;AAC3D,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE;AACjE,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;AAC/D;AACA,QAAQ,MAAM,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE;AACpC,YAAY,IAAI,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE;AAC/C,gBAAgB,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,WAAW,CAAC,EAAE;AAC3C,oBAAoB,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AAC9C;AACA,oBAAoB,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC;AACrD,oBAAoB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;AACnD,wBAAwB,EAAE,CAAC,SAAS,CAAC;AACrC,4BAA4B,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,4BAA4B,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,wBAAwB,EAAE;AAC1B,gBAAgB,CAAC;AACjB,gBAAgB,KAAK,CAAC;AACtB,YAAY,IAAI,CAAC,CAAC,QAAQ,EAAE;AAC5B,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAC9C,oBAAoB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzD,wBAAwB,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC;AAC9D,wBAAwB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;AACvD,4BAA4B,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvE,wBAAwB,EAAE;AAC1B,oBAAoB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/D,wBAAwB,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACxE,4BAA4B,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC/C,4BAA4B,EAAE,QAAQ,CAAC,MAAM,CAAC;AAC9C,wBAAwB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;AACvD,4BAA4B,EAAE,CAAC,SAAS,CAAC;AACzC,gCAAgC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjG,gCAAgC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACtD,4BAA4B,CAAC;AAC7B,wBAAwB,EAAE;AAC1B,oBAAoB,CAAC,CAAC,IAAI,CAAC,CAAC;AAC5B,wBAAwB,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM;AAClF,wBAAwB,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC1D,4BAA4B,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC;AAC7D,4BAA4B,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE;AACxE,wBAAwB,CAAC;AACzB,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB,gBAAgB,KAAK,CAAC;AACtB,YAAY,IAAI,CAAC,CAAC,KAAK,EAAE;AACzB,gBAAgB,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC;AACpD,gBAAgB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,EAAE;AACtD,gBAAgB,KAAK,CAAC;AACtB,QAAQ,CAAC;AACT;AACA,YAAY,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM;AACjD,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;AAC1D,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,MAAM;AACrC,YAAY,IAAI,CAAC;AACjB,YAAY,GAAG,CAAC;AAChB,YAAY,CAAC,CAAC;AACd;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9C,YAAY,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9B,YAAY,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE;AACvC;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,gBAAgB,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,oBAAoB,kBAAkB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACpE,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY;AACrE,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AAC5B,YAAY,CAAC;AACb,gBAAgB,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE;AACpD,gBAAgB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACrC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC;AAClB,gBAAgB,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE;AACxD,gBAAgB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACrC,YAAY,CAAC;AACb,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO;AAClE,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AAC9B,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE;AAChD,YAAY,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACjC,QAAQ,EAAE;AACV;AACA,IAAI,KAAK;AACT;AACA;AACA,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS;AAC5E,IAAI,EAAE,MAAM,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ;AAC9E,IAAI,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO;AAC5E,IAAI,EAAE,MAAM,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;AAChF,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;AAC3C,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI;AACvE,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,WAAW,CAAC;AAC5C,KAAK,CAAC,CAAC,CAAC,MAAM;AACd,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,EAAE;AACP,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE;AACvC,YAAY,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;AAC3C,QAAQ,EAAE;AACV;AACA,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AACnC,QAAQ,GAAG,CAAC,IAAI,YAAY,CAAC;AAC7B,QAAQ,KAAK,CAAC,EAAE,YAAY,CAAC;AAC7B,QAAQ,IAAI,CAAC,GAAG,YAAY,CAAC;AAC7B,QAAQ,IAAI,CAAC,GAAG,YAAY,CAAC;AAC7B,QAAQ,KAAK,CAAC,EAAE,YAAY,CAAC;AAC7B,QAAQ,MAAM,CAAC,CAAC,YAAY;AAC5B,IAAI,EAAE;AACN;AACA;AACA,IAAI,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,qBAAqB,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC;AAC9E,IAAI,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;AACzD,IAAI,EAAE,CAAC,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,qBAAqB,CAAC;AACtF,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpB;AACA,QAAQ,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,cAAc;AAC/C,QAAQ,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,EAAE;AAC9D,YAAY,CAAC,CAAC,wBAAwB,CAAC,EAAE;AACzC,YAAY,CAAC,CAAC,2BAA2B,CAAC,EAAE;AAC5C,YAAY,CAAC,CAAC,uBAAuB,CAAC;AACtC;AACA,QAAQ,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,EAAE;AAC5D,YAAY,CAAC,CAAC,uBAAuB,CAAC,EAAE;AACxC,YAAY,CAAC,CAAC,0BAA0B,CAAC,EAAE;AAC3C,YAAY,CAAC,CAAC,sBAAsB,CAAC;AACrC;AACA,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS;AACnC,QAAQ,EAAE,CAAC,CAAC,CAAC,qBAAqB,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;AAC9D,YAAY,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI;AAC9E,YAAY,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC;AAC/E,YAAY,EAAE,qBAAqB,CAAC,CAAC,CAAC,QAAQ,GAAG;AACjD,gBAAgB,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE;AACnE,YAAY,EAAE;AACd,YAAY,EAAE,oBAAoB,CAAC,CAAC,CAAC,QAAQ,GAAG;AAChD,gBAAgB,MAAM,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE;AAClE,YAAY,EAAE;AACd,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG;AAChC,gBAAgB,UAAU,CAAC,CAAC,CAAC,GAAG;AAChC,gBAAgB,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,gBAAgB,WAAW,CAAC;AAC5B;AACA,YAAY,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,QAAQ;AAC3D,YAAY,EAAE,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC5D,gBAAgB,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;AAC9D;AACA,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACrC,oBAAoB,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC3D,wBAAwB,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAClD,4BAA4B,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AAC/C,4BAA4B,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,WAAW,CAAC,KAAK;AAC7E,4BAA4B,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG;AAC3E,4BAA4B,EAAE,CAAC,UAAU,CAAC;AAC1C,4BAA4B,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG;AAC/E,4BAA4B,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC;AACjD,4BAA4B,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC;AAClD,4BAA4B,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC;AACpD,4BAA4B,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9C,4BAA4B,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACzD,gCAAgC,UAAU,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;AAChE,4BAA4B,CAAC;AAC7B,wBAAwB,CAAC,CAAC,IAAI,CAAC,CAAC;AAChC,4BAA4B,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,WAAW;AAC1E,4BAA4B,aAAa,CAAC,CAAC,WAAW,CAAC,EAAE;AACzD,4BAA4B,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;AACpD,wBAAwB,CAAC;AACzB,oBAAoB,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM;AAClF,gBAAgB,CAAC;AACjB;AACA,gBAAgB,MAAM,CAAC,UAAU,CAAC;AAClC,YAAY,EAAE;AACd;AACA,YAAY,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,QAAQ;AAC1D,YAAY,EAAE,oBAAoB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC5D,gBAAgB,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACpD,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzB,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,oBAAoB,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC/D,wBAAwB,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAClD,wBAAwB,MAAM,CAAC;AAC/B,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB;AACA,gBAAgB,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS;AACjF,gBAAgB,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,oBAAoB,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC9E,gBAAgB,EAAE,CAAC,qBAAqB,CAAC,QAAQ,EAAE;AACnD,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,oBAAoB,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC/D,wBAAwB,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAClD,wBAAwB,MAAM,CAAC;AAC/B,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB,YAAY,EAAE;AACd,QAAQ,CAAC;AACT,IAAI,GAAG,CAAC,MAAM,CAAC,EAAE;AACjB;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AAC/B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;AACjC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;AACzB,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClD,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpD,YAAY,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;AACjC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC;AACxC,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,EAAE,aAAa,GAAG;AAClB;AACA;AACA,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG;AAC5E,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3B,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AAC/B,QAAQ,MAAM,IAAI,CAAC,OAAO,EAAE;AAC5B,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;AAC9D,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM;AACpC,QAAQ,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,GAAG;AACnC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,aAAa;AACzC,QAAQ,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,GAAG;AACvC,IAAI,CAAC;AACL,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACrB,IAAI,MAAM,CAAC,aAAa,CAAC;AACzB,IAAI;;ACpoFJ,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS;AAChD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChB,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;AACxE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa;AAC5B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC;AAC1F,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;AACtF,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;AAClG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;AACvF,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;AACnF,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC;AACpF,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AAC3F,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,wBAAwB,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;AACnF,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AAClC,KAAK,EAAE;AACP,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AACzB,QAAQ,kBAAkB,CAAC,CAAC,KAAK,CAAC;AAClC,QAAQ,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE;AACnD,QAAQ,oBAAoB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE;AAC1D,QAAQ,iBAAiB,CAAC,CAAC,QAAQ,EAAE,CAAC,GAAG;AACzC,QAAQ,cAAc,CAAC,CAAC,QAAQ,EAAE,CAAC,GAAG;AACtC,QAAQ,gBAAgB,CAAC,CAAC,QAAQ,EAAE,CAAC,GAAG;AACxC,QAAQ,mBAAmB,CAAC,CAAC,GAAG;AAChC,QAAQ,wBAAwB,CAAC,CAAC,EAAE;AACpC,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO;AAC/B,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AACpC,QAAQ,EAAE,CAAC,GAAG,CAAC,QAAQ;AACvB,QAAQ,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC;AAChD,QAAQ,aAAa,CAAC,oBAAoB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACzD,YAAY,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAC;AAC9C,QAAQ,EAAE;AACV,QAAQ,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC/D,YAAY,MAAM,CAAC,OAAO,CAAC,iBAAiB,GAAG;AAC/C,QAAQ,EAAE;AACV,QAAQ,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACnD,YAAY,QAAQ,CAAC,cAAc,GAAG;AACtC,QAAQ,EAAE;AACV,QAAQ,aAAa,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,gBAAgB,EAAE;AAC/D,QAAQ,aAAa,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,eAAe,EAAE;AACnE,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAC7C,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE;AAChB,QAAQ,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC;AAChD,QAAQ,aAAa,CAAC,oBAAoB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACzD,YAAY,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC;AAChD,QAAQ,EAAE;AACV,QAAQ,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC/D,YAAY,MAAM,CAAC,OAAO,CAAC,mBAAmB,GAAG;AACjD,QAAQ,EAAE;AACV,QAAQ,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACnD,YAAY,QAAQ,CAAC,gBAAgB,GAAG;AACxC,QAAQ,EAAE;AACV,QAAQ,aAAa,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,kBAAkB,EAAE;AACjE,QAAQ,aAAa,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,iBAAiB,EAAE;AACrE,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;AACjD,QAAQ,EAAE,CAAC,MAAM,CAAC,MAAM;AACxB,QAAQ,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC;AAChD,QAAQ,aAAa,CAAC,oBAAoB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACzD,YAAY,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAC;AACpD,QAAQ,EAAE;AACV,QAAQ,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC/D,YAAY,MAAM,CAAC,OAAO,CAAC,uBAAuB,GAAG;AACrD,QAAQ,EAAE;AACV,QAAQ,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACnD,YAAY,QAAQ,CAAC,oBAAoB,GAAG;AAC5C,QAAQ,EAAE;AACV,QAAQ,aAAa,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,sBAAsB,EAAE;AACrE,QAAQ,aAAa,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,qBAAqB,EAAE;AACzE,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;AACnD,QAAQ,EAAE,CAAC,GAAG,CAAC,MAAM;AACrB,QAAQ,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC;AAChD,QAAQ,aAAa,CAAC,oBAAoB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACzD,YAAY,MAAM,CAAC,QAAQ,CAAC,8BAA8B,CAAC;AAC3D,QAAQ,EAAE;AACV,QAAQ,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC/D,YAAY,MAAM,CAAC,OAAO,CAAC,uBAAuB,GAAG;AACrD,QAAQ,EAAE;AACV,QAAQ,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACnD,YAAY,QAAQ,CAAC,sBAAsB,GAAG;AAC9C,QAAQ,EAAE;AACV,QAAQ,aAAa,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,sBAAsB,EAAE;AACrE,QAAQ,aAAa,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,qBAAqB,EAAE;AACzE,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;AAChD,QAAQ,EAAE,CAAC,OAAO;AAClB,QAAQ,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC;AAChD,QAAQ,aAAa,CAAC,oBAAoB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACzD,YAAY,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAC;AACjD,QAAQ,EAAE;AACV,QAAQ,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC/D,YAAY,MAAM,CAAC,OAAO,CAAC,oBAAoB,GAAG;AAClD,QAAQ,EAAE;AACV,QAAQ,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACnD,YAAY,QAAQ,CAAC,mBAAmB,GAAG;AAC3C,QAAQ,EAAE;AACV,QAAQ,aAAa,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,mBAAmB,EAAE;AAClE,QAAQ,aAAa,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,kBAAkB,EAAE;AACtE,IAAI,CAAC;AACL,IAAI,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC7C,QAAQ,MAAM,CAAC,aAAa,CAAC,oBAAoB,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAC7D,IAAI,EAAE;AACN,IAAI,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACjD,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,gBAAgB,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,OAAO,IAAI;AACvF,QAAQ,aAAa,CAAC,cAAc,GAAG;AACvC,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG;AACjB,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,EAAE;AACjC;AACA,GAAG,CAAC,aAAa,CAAC,EAAE;;AChJpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW;AAC9B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,IAAI;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC;AACnE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY;AACzB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;AAC/E,CAAC,EAAE;AACH;AACA;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW;AACrB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,EAAE;AACH,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC5B,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG;AACrB,EAAE;AACF;AACA,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE;AACjD,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC3B;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC;AAClF,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AACzB,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC;AAC7D,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;AAChF,KAAK,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC;AACpB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS;AAChF,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AACtB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK;AAC1E,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC1B,KAAK,EAAE;AACP,IAAI,cAAc,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACnE,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACxB,QAAQ,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;AAC3B,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACtB,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAC3C,YAAY,KAAK,GAAG;AACpB,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;AAClC,gBAAgB,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE;AAC3D,YAAY,CAAC;AACb,YAAY,OAAO,CAAC,KAAK,EAAE;AAC3B,QAAQ,EAAE;AACV,QAAQ,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE;AAC1D,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC9C,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC;AAC7D,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC;AAC9F,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AAChG,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC3D,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE;AAC9C,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACxB,YAAY,IAAI,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG;AACnD,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,YAAY,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;AACvF,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AACzD,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC;AACxF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC;AAC5E,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACpD,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE;AAC9C,YAAY,QAAQ,CAAC,CAAC,CAAC,GAAG;AAC1B,YAAY,CAAC,CAAC;AACd,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACxB,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACnD,gBAAgB,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACtD,oBAAoB,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACjD,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,YAAY,IAAI,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AAChD,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG;AAChF,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;AACvD,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC;AAC1F,KAAK,EAAE;AACP,IAAI,iBAAiB,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC9C,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE;AACzB,YAAY,IAAI,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;AAC1C,QAAQ,CAAC,CAAC,IAAI,CAAC;AACf,YAAY,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAClD,gBAAgB,IAAI,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;AAC9C,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AACzH,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;AACrE,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACxC,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE;AAC9C,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC1C,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACtC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,YAAY,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACxC,QAAQ,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC1C,YAAY,GAAG,CAAC,CAAC,CAAC;AAClB,gBAAgB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;AACvC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5C,gBAAgB,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,oBAAoB,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC;AAC9C,oBAAoB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC;AACzD,oBAAoB,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE;AAChD,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC;AACnE,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC;AAC7D,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;AACvD,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAClD,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AAC1D,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,EAAE;AACrC,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,EAAE;AACnD;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACxB,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC/B,gBAAgB,SAAS,CAAC,CAAC,CAAC,GAAG;AAC/B,YAAY,CAAC;AACb;AACA,YAAY,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,EAAE;AACvC,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,EAAE;AACF;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;AC5LpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,YAAY;AAC/B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjB;AACA,IAAI,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,SAAS;AACjC,IAAI,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC,GAAG;AAC5B;AACA,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU;AACjD,IAAI,GAAG,CAAC,IAAI,WAAW,CAAC,CAAC,GAAG;AAC5B;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY;AAC1B,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ;AAC1G,KAAK,CAAC,YAAY,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC;AAC7D,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAC9B,KAAK,CAAC,MAAM,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO;AAC9E,KAAK,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ;AAChF,KAAK,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,kBAAkB,EAAE;AAC9E,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;AACnD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,OAAO;AAC9C,KAAK,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AAChF,KAAK,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC;AACrC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC;AACrD,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK;AACvE,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC;AACjF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,kBAAkB;AACjD,KAAK,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW;AACvF,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC/C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,kBAAkB;AACjD,KAAK,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK;AAC5F,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC7C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,qBAAqB;AACpD,KAAK,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AAC1F,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;AACtD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,qBAAqB;AACpD,KAAK,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM;AACzE,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC7C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;AAC7C,KAAK,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI;AAC3E,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC;AAC3B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC;AACtE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;AAClD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC;AACrE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;AACjD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC;AACtE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;AAClD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC,IAAI,CAAC;AAChF,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;AACrE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC;AACxE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,wBAAwB,CAAC,IAAI,CAAC;AAClF,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;AACvE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC;AACrE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;AACjD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC;AACvE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC;AACvD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC;AACtE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;AAClD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC;AACzE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;AACzD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC;AACrE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;AACrD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC;AACxE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AACzD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC;AACtE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;AACtD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC;AACxE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;AAC5C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC;AACtE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AAC1C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;AACpE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC7C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC;AACtE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AAC1C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC;AACrE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AACzC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;AAC9C,KAAK,CAAC,MAAM,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC;AACpF,KAAK,EAAE;AACP,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC3C;AACA,QAAQ,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACnC;AACA,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7B;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,YAAY,OAAO,CAAC,CAAC,CAAC,CAAC;AACvB,gBAAgB,OAAO,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9C,gBAAgB,kBAAkB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9C,gBAAgB,kBAAkB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7C,YAAY,EAAE;AACd,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,IAAI,eAAe,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;AACpF,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC;AACpE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AACpC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC;AAChD,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,OAAO,YAAY,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AAClE,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW;AACtF,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC9C,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,kBAAkB;AAC9C,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC;AAChD,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,kBAAkB,CAAC;AACtG,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK;AAC3F,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC5C,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,kBAAkB;AAC9C,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC;AAChD,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,kBAAkB,CAAC;AACtG,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACzF,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;AACrD,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,qBAAqB;AACjD,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC;AAChD,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,qBAAqB,CAAC;AAC/G,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM;AACxE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC5C,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,kBAAkB;AAC9C,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC;AAChD,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,qBAAqB,CAAC;AAC/G,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE;AAC1C,QAAQ,IAAI,CAAC,QAAQ,cAAc,CAAC,CAAC,OAAO,CAAC,QAAQ,UAAU,EAAE,CAAC,IAAI,CAAC;AACvE,QAAQ,IAAI,CAAC,SAAS,aAAa,CAAC,CAAC,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,EAAE,CAAC;AACrE;AACA,QAAQ,IAAI,CAAC,YAAY,aAAa,CAAC,CAAC,OAAO,CAAC,YAAY,aAAa,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,WAAW,cAAc,CAAC,CAAC,OAAO,CAAC,WAAW,cAAc,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,YAAY,aAAa,CAAC,CAAC,OAAO,CAAC,YAAY,aAAa,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,sBAAsB,GAAG,CAAC,CAAC,OAAO,CAAC,sBAAsB,GAAG,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,cAAc,WAAW,CAAC,CAAC,OAAO,CAAC,cAAc,WAAW,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC,OAAO,CAAC,wBAAwB,CAAC,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,WAAW,cAAc,CAAC,CAAC,OAAO,CAAC,WAAW,cAAc,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,aAAa,YAAY,CAAC,CAAC,OAAO,CAAC,aAAa,YAAY,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,YAAY,aAAa,CAAC,CAAC,OAAO,CAAC,YAAY,aAAa,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,eAAe,UAAU,CAAC,CAAC,OAAO,CAAC,eAAe,UAAU,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,WAAW,cAAc,CAAC,CAAC,OAAO,CAAC,WAAW,cAAc,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,cAAc,WAAW,CAAC,CAAC,OAAO,CAAC,cAAc,WAAW,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,YAAY,aAAa,CAAC,CAAC,OAAO,CAAC,YAAY,aAAa,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,WAAW,cAAc,CAAC,CAAC,OAAO,CAAC,WAAW,cAAc,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,cAAc,WAAW,CAAC,CAAC,OAAO,CAAC,cAAc,WAAW,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,YAAY,aAAa,CAAC,CAAC,OAAO,CAAC,YAAY,aAAa,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,UAAU,eAAe,CAAC,CAAC,OAAO,CAAC,UAAU,eAAe,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,YAAY,aAAa,CAAC,CAAC,OAAO,CAAC,YAAY,aAAa,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,IAAI,CAAC,WAAW,cAAc,CAAC,CAAC,OAAO,CAAC,WAAW,cAAc,EAAE,CAAC,IAAI,CAAC;AACjF,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE;AACzC;AACA,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG;AAC7D,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,OAAO;AACnB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ;AACvC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;AAC1E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,YAAY,KAAK,CAAC,iBAAiB,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACnF,YAAY,QAAQ,CAAC,cAAc,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACtF,YAAY,OAAO,CAAC,eAAe,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACrF,YAAY,KAAK,CAAC,iBAAiB,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACnF,YAAY,QAAQ,CAAC,cAAc,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACtF,YAAY,KAAK,CAAC,iBAAiB,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACnF,YAAY,IAAI,CAAC,kBAAkB,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AAClF;AACA,YAAY,KAAK,CAAC,iBAAiB,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACnF,YAAY,UAAU,CAAC,YAAY,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACxF,YAAY,cAAc,CAAC,QAAQ,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACxF,YAAY,mBAAmB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACxF;AACA,YAAY,UAAU,CAAC,YAAY,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI;AAC5G,YAAY,UAAU,CAAC,YAAY,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI;AAC5G,YAAY,SAAS,CAAC,aAAa,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACvF,YAAY,QAAQ,CAAC,cAAc,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACtF,YAAY,SAAS,CAAC,aAAa,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACvF,YAAY,OAAO,CAAC,eAAe,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACrF,YAAY,eAAe,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AAC7F,YAAY,SAAS,CAAC,aAAa,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACvF,YAAY,iBAAiB,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AAC/F;AACA,YAAY,UAAU,CAAC,YAAY,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACxF,YAAY,QAAQ,CAAC,cAAc,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACtF,YAAY,gBAAgB,CAAC,MAAM,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AAC9F,YAAY,SAAS,CAAC,aAAa,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACvF,YAAY,iBAAiB,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AAC/F,YAAY,WAAW,CAAC,WAAW,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACzF;AACA,YAAY,YAAY,CAAC,UAAU,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AAC1F,YAAY,aAAa,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AAC3F;AACA,YAAY,WAAW,CAAC,WAAW,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACzF,YAAY,aAAa,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACzF,YAAY,UAAU,CAAC,YAAY,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACxF,YAAY,YAAY,CAAC,UAAU,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACxF,YAAY,WAAW,CAAC,WAAW,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACzF,YAAY,aAAa,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACzF,YAAY,SAAS,CAAC,aAAa,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACvF,YAAY,WAAW,CAAC,WAAW,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACvF,YAAY,WAAW,CAAC,WAAW,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACzF,YAAY,aAAa,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACzF,YAAY,aAAa,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AAC3F,YAAY,eAAe,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AAC3F,YAAY,iBAAiB,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AAC/F,YAAY,mBAAmB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACjG;AACA,YAAY,QAAQ,CAAC,cAAc,KAAK,CAAC;AACzC;AACA,YAAY,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;AAC1G,YAAY,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,2BAA2B,IAAI;AAClJ,YAAY,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI;AAC5G,YAAY,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AAC7H,YAAY,mBAAmB,CAAC,GAAG,GAAG;AACtC;AACA,YAAY,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO;AAChD,YAAY,YAAY,CAAC,UAAU,IAAI,CAAC;AACxC,YAAY,eAAe,CAAC,OAAO,IAAI,CAAC;AACxC;AACA,YAAY,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO;AACzC,YAAY,YAAY,CAAC,UAAU,GAAG;AACtC,YAAY,aAAa,CAAC,SAAS,CAAC,CAAC;AACrC,YAAY,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACrC,YAAY,eAAe,CAAC,OAAO,IAAI,CAAC;AACxC,YAAY,kBAAkB,CAAC,IAAI,IAAI;AACvC,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AACvC,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE;AACrC,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,YAAY,CAAC,SAAS,CAAC,EAAE;AACtD,IAAI,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAChC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AACjE,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,EAAE;AACX,QAAQ,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC9B,YAAY,GAAG,CAAC,CAAC,CAAC;AAClB;AACA,YAAY,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE;AACjC,YAAY,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AAChC;AACA,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC1D,gBAAgB,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpD,oBAAoB,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACjD,oBAAoB,KAAK,CAAC;AAC1B,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,YAAY,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AACrC,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;AAC5D,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ;AAC7C,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;AAC/E,SAAS,EAAE;AACX,QAAQ,UAAU,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACjC,YAAY,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;AAC9C,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;AACnF,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;AACjF,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC;AAC3D,SAAS,EAAE;AACX,QAAQ,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACzC,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC1B,gBAAgB,aAAa,CAAC,CAAC,IAAI,CAAC,EAAE;AACtC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE;AACrC,YAAY,CAAC;AACb,YAAY,EAAE,KAAK;AACnB,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;AACtI,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AACxF,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,gBAAgB,EAAE;AACzE,SAAS,EAAE;AACX,QAAQ,gCAAgC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7D,YAAY,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AAC7C,YAAY,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG;AAC/B;AACA,YAAY,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC3E,gBAAgB,EAAE,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACpE,oBAAoB,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,GAAG;AACpE,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,SAAS,CAAC;AAC7B,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;AAC9H,SAAS,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;AACrJ,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AACxF,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,gBAAgB,CAAC;AACjE,SAAS,EAAE;AACX,QAAQ,2BAA2B,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACxD,YAAY,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AAC7C,gBAAgB,CAAC,CAAC;AAClB,gBAAgB,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,MAAM,CAAC;AAC1D,gBAAgB,IAAI,CAAC;AACrB;AACA,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACzC,gBAAgB,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACxE,oBAAoB,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,EAAE;AAC7D,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/D,YAAY,QAAQ,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACtD,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AACxF,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;AAC5B,SAAS,EAAE;AACX,QAAQ,qBAAqB,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC5C,YAAY,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AAC7C,gBAAgB,CAAC,CAAC;AAClB,gBAAgB,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,MAAM,CAAC;AAC1D,gBAAgB,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1B;AACA,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACzC,gBAAgB,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,GAAG;AACvE,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,KAAK,CAAC;AACzB,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,WAAW;AAC5C,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AAC5C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1E,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO;AACxC,SAAS,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;AACxC,SAAS,CAAC,MAAM,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AACjL,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC7E,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG;AAChF,SAAS,CAAC,MAAM,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AACtE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,aAAa;AAC/C,SAAS,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;AAC7I,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,YAAY;AAC9C,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;AACvK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,YAAY,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACtC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,WAAW;AAC5C,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AAC5C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1E,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO;AACxC,SAAS,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;AACxC,SAAS,CAAC,MAAM,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AACjL,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC7E,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG;AAChF,SAAS,CAAC,MAAM,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AACtE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,aAAa;AAC/C,SAAS,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;AAC7I,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,YAAY;AAC9C,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;AACvK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,WAAW,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACrC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,WAAW;AAC5C,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AAC5C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1E,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO;AACxC,SAAS,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;AACxC,SAAS,CAAC,MAAM,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AACjL,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,YAAY;AAC9C,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;AACvK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,YAAY,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACtC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,WAAW;AAC5C,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AAC5C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1E,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM;AACvC,SAAS,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC9C,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AACvH,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO;AACxC,SAAS,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;AACxC,SAAS,CAAC,MAAM,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AACjL,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,YAAY;AAC9C,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;AACvK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,sBAAsB,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AAChD;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,WAAW;AAC5C,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AAC5C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1E,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO;AACxC,SAAS,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;AACxC,SAAS,CAAC,MAAM,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AACjL,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG;AAChF,SAAS,CAAC,MAAM,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AACtE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,qBAAqB;AACvD,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC3F,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,YAAY;AAC9C,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;AACvK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,cAAc,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACxC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,WAAW;AAC5C,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AAC5C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1E,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM;AACvC,SAAS,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC9C,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AACvH,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO;AACxC,SAAS,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;AACxC,SAAS,CAAC,MAAM,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AACjL,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,YAAY;AAC9C,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;AACvK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,wBAAwB,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AAClD;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,WAAW;AAC5C,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AAC5C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1E,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO;AACxC,SAAS,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;AACxC,SAAS,CAAC,MAAM,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AACjL,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,YAAY;AAC9C,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;AACvK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,WAAW,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACrC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,WAAW;AAC5C,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AAC5C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1E,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM;AACvC,SAAS,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;AAC/C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK;AACvC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACpE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,YAAY;AAC9C,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC;AACtN,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,aAAa,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACvC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,WAAW;AAC5C,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AAC5C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1E,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK;AACvC,SAAS,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;AAC5H,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK;AACvC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACpE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,YAAY;AAC9C,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;AACvK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,YAAY,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACtC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,WAAW;AAC5C,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AAC5C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1E,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK;AACvC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACpE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,YAAY;AAC9C,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;AACvK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,eAAe,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACzC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,WAAW;AAC5C,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AAC5C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1E,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO;AACxC,SAAS,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;AACxC,SAAS,CAAC,MAAM,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AACjL,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK;AACnD,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC;AACjK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK;AACtC,SAAS,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;AAC5D,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,SAAS;AAC1C,SAAS,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACnK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK;AACvC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACpE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,YAAY;AAC9C,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;AACvK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,WAAW,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACrC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,WAAW;AAC5C,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AAC5C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1E,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK;AACtC,SAAS,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;AACxE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,SAAS;AAC1C,SAAS,CAAC,KAAK,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/K,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK;AACvC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACpE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,YAAY;AAC9C,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;AACvK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,cAAc,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACxC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,WAAW;AAC5C,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AAC5C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,aAAa;AACvF,SAAS,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;AAC5F,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,UAAU;AACxD,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1G,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM;AACpD,SAAS,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AACjG,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,YAAY;AAC7C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AACzF,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AAChF,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK;AACvC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACpE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,YAAY,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACtC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,WAAW;AAC5C,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AAC5C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1E,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO;AACxC,SAAS,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;AACxC,SAAS,CAAC,MAAM,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AACjL,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,YAAY;AAC9C,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;AACvK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,WAAW,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACrC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO;AACxC,SAAS,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;AAC9C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI;AACtC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACnE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK;AACvC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACpE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG;AACrC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AAClE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI;AACtC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACnE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,cAAc,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACxC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO;AACxC,SAAS,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;AAC9C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI;AACtC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACnE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK;AACvC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACpE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG;AACrC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AAClE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI;AACtC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACnE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,YAAY,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACtC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO;AACxC,SAAS,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;AAC9C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI;AACtC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACnE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK;AACvC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACpE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG;AACrC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AAClE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI;AACtC,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACnE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,UAAU,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACpC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,YAAY,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACtC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC/E,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,WAAW;AAChE,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,SAAS,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACtD,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACvJ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ;AACzC,SAAS,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,SAAS,EAAE;AACX,QAAQ,WAAW,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACpC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE;AACjI,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,qBAAqB;AACpC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY;AAC3C,KAAK,EAAE;AACP,IAAI,EAAE,YAAY,CAAC,qBAAqB,CAAC,CAAC,CAAC,QAAQ,GAAG;AACtD,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;AACtD,YAAY,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE,UAAU,IAAI;AAC/C,gBAAgB,aAAa,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,EAAE;AACpD,gBAAgB,aAAa,CAAC,CAAC,EAAE,WAAW,CAAC,IAAI,EAAE;AACnD,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC;AAC5F,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI;AAC9G,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,2BAA2B;AAC1C,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY;AAC3C,KAAK,EAAE;AACP,IAAI,EAAE,YAAY,CAAC,2BAA2B,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC/D,QAAQ,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG;AAC/B,YAAY,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,YAAY,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACzB;AACA,QAAQ,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK;AACpE,QAAQ,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC1D,YAAY,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,GAAG;AAChF,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;AACrF,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACvC,YAAY,GAAG,CAAC,CAAC,CAAC;AAClB,gBAAgB,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC;AAC3C,gBAAgB,UAAU,CAAC;AAC3B,gBAAgB,MAAM,CAAC;AACvB,gBAAgB,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AAC9B,gBAAgB,WAAW,CAAC;AAC5B,gBAAgB,QAAQ,CAAC;AACzB,gBAAgB,KAAK,CAAC;AACtB;AACA,YAAY,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;AACzC,YAAY,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC;AAC3B;AACA,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACzC,gBAAgB,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE;AAChD,gBAAgB,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC;AAC3C,gBAAgB,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AAChG,gBAAgB,EAAE,GAAG,GAAG,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC;AAC5E,gBAAgB,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AACxI,gBAAgB,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI;AAClD,gBAAgB,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE;AAC9E,gBAAgB,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;AACvD,gBAAgB,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9D,gBAAgB,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC;AACvH,gBAAgB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;AAClE,YAAY,CAAC;AACb,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO;AACpD,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACrD,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE;AACxD;AACA,YAAY,aAAa,CAAC,IAAI,CAAC;AAC/B,gBAAgB,CAAC;AACjB,oBAAoB,IAAI,CAAC,CAAC,IAAI,CAAC;AAC/B,oBAAoB,MAAM,CAAC,CAAC,MAAM,CAAC;AACnC,oBAAoB,OAAO,CAAC,CAAC,MAAM,CAAC,UAAU;AAC9C,gBAAgB,CAAC,CAAC,EAAE;AACpB;AACA,YAAY,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK;AACrF,YAAY,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C,gBAAgB,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AACnC,gBAAgB,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE;AACnE,YAAY,CAAC;AACb,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK;AAChD,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACxD,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE;AACxD,gBAAgB,CAAC,CAAC;AAClB,gBAAgB,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC;AAC3C,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACzC,gBAAgB,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACzD,oBAAoB,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACjD,oBAAoB,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK;AACtF,oBAAoB,GAAG,GAAG;AAC1B,oBAAoB,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtC,wBAAwB,MAAM,CAAC,aAAa,CAAC,CAAC,UAAU,CAAC,EAAE;AAC3D,oBAAoB,CAAC;AACrB,oBAAoB,KAAK,CAAC;AAC1B,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,EAAE;AACV;AACA,QAAQ,MAAM,CAAC,CAAC;AAChB,YAAY,QAAQ,CAAC,IAAI,QAAQ,CAAC;AAClC,YAAY,WAAW,CAAC,CAAC,WAAW;AACpC,QAAQ,EAAE;AACV,IAAI,CAAC,CAAC,IAAI;AACV;AACA;AACA,+EAA+E;AAC/E,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS;AAC5C,+EAA+E;AAC/E;AACA,IAAI,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC7C;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;AAC/C,KAAK,EAAE;AACP,IAAI,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACrG,gDAAgD,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AAC/I,oCAAoC,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,qBAAqB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC;AAC3J,oCAAoC,CAAC,cAAc,EAAE,wDAAwD,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO;AAClI;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;AAC3C,KAAK,EAAE;AACP,IAAI,EAAE,YAAY,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACxD,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AACzD,QAAQ,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE;AAClG,IAAI,KAAK;AACT;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC;AACzG,KAAK,EAAE;AACP,IAAI,EAAE,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,YAAY,CAAC,cAAc,CAAC,EAAE;AAC7I;AACA,IAAI,EAAE,CAAC,CAAC,EAAE,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,QAAQ,EAAE,CAAC,KAAK,CAAC,OAAO;AACxB,QAAQ,EAAE,YAAY,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,EAAE;AACrE,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAC5F,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7G,QAAQ,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC;AACpG,QAAQ,EAAE,YAAY,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC;AAChD,QAAQ,EAAE,YAAY,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE;AACvI,QAAQ,EAAE,YAAY,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAC;AACtD,QAAQ,EAAE,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AACxC,YAAY,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC;AACrE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,QAAQ,CAAC;AACT,QAAQ,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC;AAC9C,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAC9E,QAAQ,EAAE,CAAC,IAAI;AACf,QAAQ,EAAE,YAAY,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC;AAChD,QAAQ,EAAE,YAAY,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC,EAAE;AACnJ,QAAQ,EAAE,YAAY,CAAC,uBAAuB,CAAC,CAAC,CAAC,KAAK,CAAC;AACvD,QAAQ,EAAE,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAC1C,YAAY,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC;AACvE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,QAAQ,CAAC;AACT,QAAQ,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC;AAC9C,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM;AAClC,QAAQ,EAAE,YAAY,CAAC,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC;AACjD,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5E,YAAY,EAAE,YAAY,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE;AAC9E,YAAY,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,YAAY,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE;AAC3E,YAAY,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC;AAClD,QAAQ,CAAC;AACT,QAAQ,EAAE,YAAY,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACnF,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACzC,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,eAAe;AACtE,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE;AAC1D,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,iBAAiB,CAAC,SAAS,CAAC,gBAAgB,CAAC,cAAc,CAAC,cAAc,CAAC,IAAI,CAAC;AAC7J,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,iBAAiB,CAAC,SAAS,CAAC,gBAAgB,CAAC,cAAc,CAAC,cAAc,CAAC,IAAI,CAAC;AAChK,YAAY,EAAE,YAAY,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE;AACxG,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC3C,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,iBAAiB,CAAC,SAAS,CAAC,gBAAgB,CAAC,cAAc,CAAC,cAAc,CAAC,IAAI,CAAC;AAC9J,YAAY,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ;AACvE,YAAY,EAAE,YAAY,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE;AACnF,QAAQ,CAAC;AACT,QAAQ,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE;AACvD,QAAQ,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3C,IAAI,CAAC;AACL;AACA;AACA,+EAA+E;AAC/E,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ;AACvB,+EAA+E;AAC/E;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;AAC/G,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY;AACrC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY;AAC3C,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AAC5B,KAAK,CAAC,KAAK,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;AAC5F,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI;AAC9B,KAAK,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ;AACnC,KAAK,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AACpF,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS;AACpC,KAAK,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;AACzK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB;AAC/C,KAAK,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC3G,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa;AACxC,KAAK,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAClG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC/B,KAAK,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;AACxD,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS;AACnC,KAAK,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/J,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,UAAU;AACjD,KAAK,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE;AAC3K,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AACrC,KAAK,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE;AAC1I,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,OAAO;AAC9C,KAAK,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC;AACnF,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAClC,KAAK,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC;AAC1D,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,UAAU;AACjD,KAAK,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC;AACtF,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AACrC,KAAK,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC;AAC7D,KAAK,EAAE;AACP;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,gBAAgB;AAC9B,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;AACnK,KAAK,CAAC,YAAY,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI;AAC/G,KAAK,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AAC5H,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY;AAC3C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AACpF,KAAK,EAAE;AACP,IAAI,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACzD,QAAQ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG;AAC3B,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AACjE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI;AAChC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC,gBAAgB,CAAC;AACjE,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;AAClD,SAAS,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AAC5K,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC,gBAAgB,CAAC;AACjE,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AACzB,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;AAC5F,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AACpC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC,gBAAgB,CAAC;AACjE,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1B,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;AAC7F,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AAClC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC,gBAAgB,CAAC;AACjE,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACxB,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;AAC9D,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY;AACxC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC,gBAAgB,CAAC;AACjE,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,IAAI,EAAE;AACN;AACA,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,YAAY,CAAC,gBAAgB,CAAC,SAAS,CAAC,EAAE;AACvE,IAAI,EAAE,YAAY,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACjD,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAClE,SAAS,EAAE;AACX,QAAQ,SAAS,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAChC,YAAY,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;AACxC,QAAQ,EAAE;AACV,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE;AACrI,SAAS,EAAE;AACX,QAAQ,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC9B,YAAY,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;AACjC,QAAQ,EAAE;AACV,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAC9G,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAClE,SAAS,EAAE;AACX,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9B,YAAY,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE;AAC5C,QAAQ,EAAE;AACV,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AACpF,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAClE,SAAS,EAAE;AACX,QAAQ,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACrC,YAAY,GAAG,CAAC,CAAC,CAAC;AAClB,gBAAgB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;AAC3C,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACzC,gBAAgB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACrD,oBAAoB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACjD,oBAAoB,KAAK,CAAC;AAC1B,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;AACxC,QAAQ,EAAE;AACV,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AAC5F,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AAC9H,SAAS,EAAE;AACX,QAAQ,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxC,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AAChD,gBAAgB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AAC9C,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,EAAE;AACV,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AACtF,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7H,SAAS,EAAE;AACX,QAAQ,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAClC,YAAY,GAAG,CAAC,CAAC,CAAC;AAClB,gBAAgB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;AAC3C,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACzC,gBAAgB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACrD,oBAAoB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,EAAE;AACV,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AAC/H,SAAS,EAAE;AACX,QAAQ,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACrC,YAAY,GAAG,CAAC,CAAC,CAAC;AAClB,gBAAgB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;AAC3C,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACzC,gBAAgB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;AACrD,oBAAoB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AAClD,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;AAC3F,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,EAAE;AACX,QAAQ,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAChC,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC;AAC5B;AACA,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;AACtF,gBAAgB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAClC,YAAY,CAAC;AACb,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AAClD,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;AAC3D,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,EAAE;AACX,QAAQ,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACnC,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC;AAC5B;AACA,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,gBAAgB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAClC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA;AACA,+EAA+E;AAC/E,EAAE,CAAC,OAAO,CAAC,SAAS;AACpB,+EAA+E;AAC/E;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpC,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,oBAAoB,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC9C,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AAC5C,YAAY,CAAC,CAAC;AACd,YAAY,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,MAAM,CAAC;AACnE;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAClD,YAAY,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvE,gBAAgB,EAAE,WAAW,CAAC;AAC9B,oBAAoB,EAAE,YAAY,CAAC,cAAc,CAAC;AAClD,oBAAoB,CAAC,SAAS,EAAE;AAChC,oBAAoB,QAAQ,CAAC,iBAAiB,CAAC;AAC/C,oBAAoB,IAAI;AACxB,gBAAgB,EAAE;AAClB,gBAAgB,EAAE,WAAW,CAAC;AAC9B,oBAAoB,EAAE,YAAY,CAAC,cAAc,CAAC;AAClD,oBAAoB,CAAC,OAAO,EAAE;AAC9B,oBAAoB,QAAQ,CAAC,eAAe,CAAC;AAC7C,oBAAoB,IAAI;AACxB,gBAAgB,EAAE;AAClB,gBAAgB,EAAE,WAAW,CAAC;AAC9B,oBAAoB,EAAE,YAAY,CAAC,cAAc,CAAC;AAClD,oBAAoB,EAAE,YAAY,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE;AAC7F,oBAAoB,QAAQ,CAAC,mBAAmB,CAAC;AACjD,oBAAoB,IAAI;AACxB,gBAAgB,EAAE;AAClB,gBAAgB,EAAE,WAAW,CAAC;AAC9B,oBAAoB,EAAE,YAAY,CAAC,cAAc,CAAC;AAClD,oBAAoB,EAAE,YAAY,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;AACzF,oBAAoB,QAAQ,CAAC,iBAAiB,CAAC;AAC/C,oBAAoB,IAAI;AACxB,gBAAgB,EAAE;AAClB,gBAAgB,EAAE,WAAW,CAAC;AAC9B,oBAAoB,EAAE,YAAY,CAAC,cAAc,CAAC;AAClD,oBAAoB,CAAC,SAAS,EAAE;AAChC,oBAAoB,QAAQ,CAAC,iBAAiB,CAAC;AAC/C,oBAAoB,IAAI;AACxB,gBAAgB,EAAE;AAClB,gBAAgB,EAAE,WAAW,CAAC;AAC9B,oBAAoB,EAAE,YAAY,CAAC,cAAc,CAAC;AAClD,oBAAoB,CAAC,QAAQ,EAAE;AAC/B,oBAAoB,QAAQ,CAAC,gBAAgB,CAAC;AAC9C,oBAAoB,IAAI;AACxB,gBAAgB,EAAE;AAClB;AACA,gBAAgB,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAClD,YAAY,QAAQ,CAAC,mBAAmB,CAAC,GAAG,GAAG;AAC/C,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC7D,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACvC,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AAC5C,YAAY,KAAK,CAAC;AAClB,YAAY,CAAC,CAAC;AACd;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACnC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC3E,gBAAgB,KAAK,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE;AAC5D,gBAAgB,EAAE,QAAQ,CAAC;AAC3B,oBAAoB,OAAO,CAAC,OAAO,CAAC;AACpC,oBAAoB,KAAK,CAAC;AAC1B,oBAAoB,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACtC,oBAAoB,KAAK;AACzB,gBAAgB,EAAE;AAClB,YAAY,CAAC;AACb;AACA,YAAY,oBAAoB,CAAC,CAAC,OAAO,CAAC,EAAE;AAC5C;AACA,YAAY,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5D,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACtC,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AAC5C,YAAY,KAAK,CAAC;AAClB,YAAY,CAAC,CAAC;AACd;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAClC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC3E,gBAAgB,KAAK,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE;AAC5D,gBAAgB,EAAE,WAAW,CAAC;AAC9B,oBAAoB,OAAO,CAAC,OAAO,CAAC;AACpC,oBAAoB,KAAK,CAAC;AAC1B,oBAAoB,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACtC,oBAAoB,KAAK;AACzB,gBAAgB,EAAE;AAClB,YAAY,CAAC;AACb;AACA,YAAY,oBAAoB,CAAC,CAAC,OAAO,CAAC,EAAE;AAC5C;AACA,YAAY,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AACtC,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC5D,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AAC5C;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C,YAAY,MAAM,CAAC,CAAC;AACpB,gBAAgB,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;AAC7F,gBAAgB,SAAS,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC;AACtD,gBAAgB,QAAQ,CAAC,CAAC,EAAE,YAAY,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE;AACnG,gBAAgB,WAAW,CAAC,CAAC,QAAQ,CAAC,mBAAmB;AACzD,YAAY,EAAE;AACd,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C,YAAY,MAAM,CAAC,CAAC;AACpB,gBAAgB,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE;AAClC,gBAAgB,SAAS,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC;AACpD,gBAAgB,QAAQ,CAAC,CAAC,CAAC,SAAS,EAAE;AACtC,gBAAgB,WAAW,CAAC,CAAC,QAAQ,CAAC,iBAAiB;AACvD,YAAY,EAAE;AACd,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C,YAAY,MAAM,CAAC,CAAC;AACpB,gBAAgB,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE;AACnC,gBAAgB,SAAS,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC;AACrD,gBAAgB,QAAQ,CAAC,CAAC,CAAC,SAAS,EAAE;AACtC,gBAAgB,WAAW,CAAC,CAAC,QAAQ,CAAC,iBAAiB;AACvD,YAAY,EAAE;AACd,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE;AAC3F,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC7D,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACnE,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,WAAW,CAAC,EAAE;AAC5E,YAAY,WAAW,CAAC;AACxB;AACA,QAAQ,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,EAAE;AACvD;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChF,gBAAgB,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE;AACnD,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,WAAW,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,YAAY,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE;AAChI,gBAAgB,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;AACxF,gBAAgB,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;AAC1G,gBAAgB,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM;AAChE,gBAAgB,EAAE,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;AAChE,oBAAoB,EAAE,QAAQ,CAAC;AAC/B,wBAAwB,MAAM,CAAC,GAAG,CAAC;AACnC,wBAAwB,WAAW,CAAC,MAAM,CAAC;AAC3C,wBAAwB,WAAW,CAAC,SAAS,CAAC;AAC9C,wBAAwB,IAAI;AAC5B,oBAAoB,EAAE;AACtB,gBAAgB,CAAC;AACjB,gBAAgB,EAAE,QAAQ,CAAC;AAC3B,oBAAoB,EAAE,YAAY,CAAC,cAAc,CAAC;AAClD,oBAAoB,WAAW,CAAC,MAAM,CAAC;AACvC,oBAAoB,WAAW,CAAC,SAAS,CAAC;AAC1C,oBAAoB,IAAI;AACxB,gBAAgB,EAAE;AAClB,gBAAgB,EAAE,QAAQ,CAAC;AAC3B,oBAAoB,EAAE,YAAY,CAAC,cAAc,CAAC;AAClD,oBAAoB,WAAW,CAAC,QAAQ,CAAC;AACzC,oBAAoB,WAAW,CAAC,WAAW,CAAC;AAC5C,oBAAoB,IAAI;AACxB,gBAAgB,EAAE;AAClB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5D,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACnE,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,WAAW,CAAC,EAAE;AAC5E,YAAY,WAAW,CAAC;AACxB;AACA,QAAQ,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,EAAE;AACvD;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChF,gBAAgB,OAAO,CAAC,OAAO,CAAC,cAAc,GAAG;AACjD,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,WAAW,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,YAAY,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE;AAChI,gBAAgB,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;AACxF,gBAAgB,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;AAC1G,gBAAgB,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM;AAChE,gBAAgB,EAAE,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;AAChE,oBAAoB,EAAE,WAAW,CAAC;AAClC,wBAAwB,MAAM,CAAC,GAAG,CAAC;AACnC,wBAAwB,WAAW,CAAC,MAAM,CAAC;AAC3C,wBAAwB,WAAW,CAAC,SAAS,CAAC;AAC9C,wBAAwB,IAAI;AAC5B,oBAAoB,EAAE;AACtB,gBAAgB,CAAC;AACjB,gBAAgB,EAAE,WAAW,CAAC;AAC9B,oBAAoB,EAAE,YAAY,CAAC,cAAc,CAAC;AAClD,oBAAoB,WAAW,CAAC,QAAQ,CAAC;AACzC,oBAAoB,WAAW,CAAC,WAAW,CAAC;AAC5C,oBAAoB,IAAI;AACxB,gBAAgB,EAAE;AAClB,gBAAgB,EAAE,WAAW,CAAC;AAC9B,oBAAoB,EAAE,YAAY,CAAC,cAAc,CAAC;AAClD,oBAAoB,WAAW,CAAC,MAAM,CAAC;AACvC,oBAAoB,WAAW,CAAC,SAAS,CAAC;AAC1C,oBAAoB,IAAI;AACxB,gBAAgB,EAAE;AAClB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;AAC/F,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AACvH,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACtC,QAAQ,GAAG,CAAC,cAAc,CAAC;AAC3B,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC;AACvD,YAAY,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AAC/C,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,CAAC,IAAI;AACnB,YAAY,EAAE,EAAE,oBAAoB,CAAC,CAAC,UAAU;AAChD,YAAY,EAAE,EAAE,kBAAkB,CAAC,GAAG,UAAU;AAChD,YAAY,EAAE,EAAE,oBAAoB,CAAC,CAAC,UAAU;AAChD,YAAY,MAAM,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;AACvC,YAAY,CAAC;AACb,gBAAgB,IAAI,CAAC,UAAU,CAAC;AAChC,oBAAoB,cAAc,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;AAC7C,oBAAoB,KAAK,CAAC;AAC1B,gBAAgB,IAAI,CAAC,UAAU,CAAC;AAChC,oBAAoB,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AAC3C,oBAAoB,KAAK,CAAC;AAC1B,gBAAgB,IAAI,CAAC,UAAU,CAAC;AAChC,oBAAoB,cAAc,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;AAC7C,oBAAoB,KAAK,CAAC;AAC1B,gBAAgB,OAAO,CAAC;AACxB,oBAAoB,cAAc,CAAC,CAAC,CAAC,GAAG;AACxC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,cAAc,CAAC;AAC9B,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxC,QAAQ,MAAM,CAAC,EAAE,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3C,IAAI,CAAC;AACL;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACjD,QAAQ,MAAM,CAAC,0BAA0B,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE;AAChF,IAAI,CAAC;AACL;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,0BAA0B,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC3D,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,OAAO,CAAC,EAAE;AACnD,QAAQ,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE;AACrC,IAAI,CAAC;AACL;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC/C,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACvF,IAAI,CAAC;AACL;AACA;AACA,+EAA+E;AAC/E,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ;AACrC,+EAA+E;AAC/E;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxC,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACrC,YAAY,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACnC,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3C,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AACxC,YAAY,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACnC,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC1C,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;AAChI,QAAQ,GAAG,CAAC,SAAS,CAAC;AACtB,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AACvC,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACxC,YAAY,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC;AAC/C,gBAAgB,CAAC;AACjB,oBAAoB,WAAW,CAAC,UAAU,OAAO,CAAC;AAClD,oBAAoB,OAAO,CAAC,cAAc,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACzF,oBAAoB,IAAI,CAAC,iBAAiB,KAAK,CAAC,OAAO,CAAC;AACxD,oBAAoB,KAAK,CAAC,gBAAgB,KAAK,CAAC,QAAQ,CAAC;AACzD,oBAAoB,GAAG,CAAC,kBAAkB,KAAK,CAAC,MAAM,CAAC;AACvD,oBAAoB,IAAI,CAAC,iBAAiB,KAAK,CAAC,OAAO,CAAC;AACxD,oBAAoB,aAAa,CAAC,QAAQ,KAAK,CAAC;AAChD,oBAAoB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AAChD,oBAAoB,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AAC1D,gBAAgB,CAAC;AACjB,YAAY,EAAE;AACd,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC/B,gBAAgB,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACvC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;AAC9H,QAAQ,GAAG,CAAC,SAAS,CAAC;AACtB,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACrC,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACxC,YAAY,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;AAC7C,gBAAgB,CAAC;AACjB,oBAAoB,WAAW,CAAC,UAAU,OAAO,CAAC;AAClD,oBAAoB,OAAO,CAAC,cAAc,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACzF,oBAAoB,IAAI,CAAC,iBAAiB,KAAK,CAAC,OAAO,CAAC;AACxD,oBAAoB,KAAK,CAAC,gBAAgB,KAAK,CAAC,QAAQ,CAAC;AACzD,oBAAoB,GAAG,CAAC,kBAAkB,KAAK,CAAC,MAAM,CAAC;AACvD,oBAAoB,IAAI,CAAC,iBAAiB,KAAK,CAAC,OAAO,CAAC;AACxD,oBAAoB,aAAa,CAAC,QAAQ,KAAK,CAAC;AAChD,oBAAoB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AAChD,oBAAoB,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AAC1D,gBAAgB,CAAC;AACjB,YAAY,EAAE;AACd,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC/B,gBAAgB,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACvC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3C,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;AACjI,QAAQ,GAAG,CAAC,SAAS,CAAC;AACtB,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACnC,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACxC,YAAY,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;AAC3C,gBAAgB,CAAC;AACjB,oBAAoB,WAAW,CAAC,UAAU,OAAO,CAAC;AAClD,oBAAoB,OAAO,CAAC,cAAc,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACzF,oBAAoB,IAAI,CAAC,iBAAiB,KAAK,CAAC,OAAO,CAAC;AACxD,oBAAoB,KAAK,CAAC,gBAAgB,KAAK,CAAC,QAAQ,CAAC;AACzD,oBAAoB,GAAG,CAAC,kBAAkB,KAAK,CAAC,MAAM,CAAC;AACvD,oBAAoB,IAAI,CAAC,iBAAiB,KAAK,CAAC,OAAO,CAAC;AACxD,oBAAoB,aAAa,CAAC,QAAQ,KAAK,CAAC;AAChD,oBAAoB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AAChD,oBAAoB,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AAC1D,gBAAgB,CAAC;AACjB,YAAY,EAAE;AACd,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC/B,gBAAgB,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACvC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE;AAC3C,QAAQ,GAAG,CAAC,SAAS,CAAC;AACtB,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACrC,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACxC,YAAY,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;AAC7C,gBAAgB,CAAC;AACjB,oBAAoB,WAAW,CAAC,UAAU,OAAO,CAAC;AAClD,oBAAoB,aAAa,CAAC,QAAQ,KAAK,CAAC;AAChD,oBAAoB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AAChD,oBAAoB,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AAC1D,gBAAgB,CAAC;AACjB,YAAY,EAAE;AACd,YAAY,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxC,gBAAgB,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACvC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACvC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE;AAC1C,QAAQ,GAAG,CAAC,SAAS,CAAC;AACtB,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACpC,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACxC,YAAY,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;AAC5C,gBAAgB,CAAC;AACjB,oBAAoB,WAAW,CAAC,UAAU,OAAO,CAAC;AAClD,oBAAoB,aAAa,CAAC,QAAQ,KAAK,CAAC;AAChD,oBAAoB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AAChD,oBAAoB,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AAC1D,gBAAgB,CAAC;AACjB,YAAY,EAAE;AACd,YAAY,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxC,gBAAgB,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACvC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM;AACjC,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxC,QAAQ,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE;AAClD,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,cAAc,EAAE,CAAC,GAAG,CAAC,CAAC,mBAAmB,CAAC,CAAC,MAAM;AACnF,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7C,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACpC;AACA,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK;AACnC,QAAQ,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AAC9B,YAAY,MAAM,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC;AACzD,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;AAChC,YAAY,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC;AAChD,YAAY,OAAO,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC;AACtC,YAAY,OAAO,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC;AACtC,YAAY,KAAK,CAAC,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAClE,YAAY,KAAK,CAAC,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAClE,YAAY,SAAS,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;AAC/F,YAAY,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1B,YAAY,MAAM,CAAC,KAAK,CAAC;AACzB,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,SAAS,CAAC,MAAM;AAC3B,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D,YAAY,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,gBAAgB,CAAC,kBAAkB,CAAC;AAC9F,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;AACjD,QAAQ,CAAC;AACT;AACA,QAAQ,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3D,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;AAC9B,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,YAAY,IAAI;AAC3F,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AAChE,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACvB,YAAY,SAAS,CAAC;AACtB;AACA,QAAQ,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS;AAC3E,QAAQ,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK;AAChF,QAAQ,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AAC/B,QAAQ,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;AACnD,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,SAAS,CAAC,OAAO;AACtJ,QAAQ,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3C;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AACtC,YAAY,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;AAC9C,gBAAgB,CAAC;AACjB,oBAAoB,WAAW,CAAC,UAAU,OAAO,CAAC;AAClD,oBAAoB,WAAW,CAAC,UAAU,CAAC,KAAK,EAAE;AAClD,oBAAoB,QAAQ,CAAC,aAAa,gBAAgB,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AACrF,oBAAoB,MAAM,CAAC,eAAe,MAAM,CAAC;AACjD,oBAAoB,KAAK,CAAC,gBAAgB,KAAK,CAAC,QAAQ,CAAC;AACzD,oBAAoB,YAAY,CAAC,SAAS,KAAK,CAAC;AAChD,oBAAoB,aAAa,CAAC,QAAQ,aAAa,CAAC;AACxD,oBAAoB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AAChD,oBAAoB,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AAC1D,gBAAgB,CAAC;AACjB,YAAY,EAAE;AACd,YAAY,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxC,gBAAgB,EAAE,WAAW,CAAC,CAAC,aAAa,CAAC,EAAE;AAC/C,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC;AAC3C,IAAI,CAAC;AACL,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChC,WAAW,MAAM,CAAC,KAAK,CAAC;AACxB,OAAO,CAAC;AACR,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5C,WAAW,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC;AACpC,OAAO,CAAC;AACR,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;AAC/B,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACxB,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7C,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACpC;AACA,QAAQ,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3C,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5C,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACpC;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzH,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3C,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACjD,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACtB,YAAY,EAAE,CAAC,CAAC,EAAE,YAAY,CAAC,cAAc,CAAC;AAC9C,YAAY,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE;AAC1B,YAAY,SAAS,CAAC,CAAC,IAAI,CAAC;AAC5B,YAAY,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE;AAClD,YAAY,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE;AAChC,QAAQ,EAAE;AACV;AACA,QAAQ,mBAAmB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AAC1D,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACxB,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7C,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACpC;AACA,QAAQ,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE;AAC1C,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3C,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACpC;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzH,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE;AAC1C,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACtB,YAAY,EAAE,CAAC,CAAC,EAAE,YAAY,CAAC,cAAc,CAAC;AAC9C,YAAY,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE;AAC1B,YAAY,SAAS,CAAC,CAAC,IAAI,CAAC;AAC5B,YAAY,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE;AAClD,YAAY,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE;AAChC,QAAQ,EAAE;AACV;AACA,QAAQ,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACzD,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC;AACtF,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC;AAC3H,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC9C,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5E,YAAY,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AACvJ,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACvE,YAAY,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjC,gBAAgB,MAAM,CAAC,CAAC,CAAC;AACzB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxC,gBAAgB,MAAM,CAAC,CAAC,CAAC;AACzB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxC,gBAAgB,MAAM,CAAC,CAAC,CAAC;AACzB,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,MAAM,CAAC,CAAC,CAAC,CAAC;AAC1B,YAAY,CAAC;AACb,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,MAAM,CAAC,MAAM,CAAC;AAC1B,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5C,QAAQ,GAAG,CAAC,MAAM,CAAC;AACnB;AACA,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACpC;AACA,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC;AAClB,YAAY,EAAE,CAAC,CAAC,EAAE,YAAY,CAAC,cAAc,CAAC;AAC9C,YAAY,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE;AAC1B,YAAY,SAAS,CAAC,CAAC,IAAI,CAAC;AAC5B,YAAY,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE;AAClD,YAAY,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE;AAChC,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,qBAAqB,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxG,YAAY,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE;AACjC,YAAY,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AAC/C,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AACzI,YAAY,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACnC,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC1C,QAAQ,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE;AACxC,IAAI,CAAC;AACL;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;AACrG,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;AACzG,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClD,QAAQ,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE;AACxC,QAAQ,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE;AAC7B,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9C,QAAQ,GAAG,CAAC,MAAM,CAAC;AACnB;AACA,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACpC;AACA,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC;AAClB,YAAY,EAAE,CAAC,CAAC,EAAE,YAAY,CAAC,cAAc,CAAC;AAC9C,YAAY,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE;AAC1B,YAAY,SAAS,CAAC,CAAC,IAAI,CAAC;AAC5B,YAAY,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE;AAClD,YAAY,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE;AAChC,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,qBAAqB,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtG,YAAY,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AAC/C,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5C,QAAQ,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE;AAC1C,GAAG,CAAC;AACJ;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;AACrG,KAAK,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;AAC3G,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpD,QAAQ,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE;AAC1C,QAAQ,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE;AAC7B,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,QAAQ,GAAG,CAAC,MAAM,CAAC;AACnB;AACA,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACpC;AACA,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC;AAClB,YAAY,EAAE,CAAC,CAAC,EAAE,YAAY,CAAC,cAAc,CAAC;AAC9C,YAAY,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE;AAC1B,YAAY,SAAS,CAAC,CAAC,IAAI,CAAC;AAC5B,YAAY,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE;AAClD,YAAY,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE;AAChC,QAAQ,EAAE;AACV;AACA,QAAQ,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACzD,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC1D,QAAQ,GAAG,CAAC,CAAC,CAAC;AACd,YAAY,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,GAAG;AACjD,YAAY,YAAY,CAAC,CAAC,CAAC,GAAG;AAC9B;AACA,QAAQ,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ;AAC1E,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACjD,gBAAgB,YAAY,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAChE,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,gBAAgB,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO;AAC5C,gBAAgB,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO;AAC7H,gBAAgB,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO;AAC1C,gBAAgB,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,gBAAgB,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE;AAC3D,gBAAgB,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ;AAC/C,gBAAgB,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,EAAE;AACnE,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7C,QAAQ,GAAG,CAAC,IAAI,CAAC;AACjB,YAAY,CAAC,CAAC;AACd,YAAY,CAAC,CAAC;AACd,YAAY,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC;AACrD,YAAY,OAAO,CAAC,CAAC,CAAC,GAAG;AACzB,YAAY,aAAa,CAAC;AAC1B,YAAY,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AACxE;AACA,QAAQ,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AACvB;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC3E,YAAY,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,IAAI;AACpI,YAAY,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,EAAE;AACxD,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5C,YAAY,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3B,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC;AACzD,gBAAgB,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE;AAC9B,gBAAgB,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;AACpF,gBAAgB,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC1E,gBAAgB,WAAW,CAAC,CAAC,IAAI;AACjC,YAAY,CAAC,CAAC,EAAE;AAChB,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO;AACrD,QAAQ,mBAAmB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE;AACvD;AACA,QAAQ,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ;AACjF,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACtD,YAAY,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtJ,gBAAgB,aAAa,CAAC,CAAC,CAAC,GAAG;AACnC,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACpD,oBAAoB,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;AACzC,wBAAwB,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC;AACjE,wBAAwB,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE;AACtC,wBAAwB,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;AAC5F,wBAAwB,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAClF,wBAAwB,WAAW,CAAC,CAAC,IAAI;AACzC,oBAAoB,CAAC,CAAC,EAAE;AACxB,gBAAgB,CAAC;AACjB,gBAAgB,mBAAmB,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,EAAE;AAChF,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO;AAC1H,YAAY,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE;AACjC,YAAY,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,UAAU,CAAC,EAAE;AAC3D,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC/B,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3C,QAAQ,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE;AACzC,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;AACvG,KAAK,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;AAC1G,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnD,QAAQ,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE;AACzC,QAAQ,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE;AAC7B,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC/C,QAAQ,GAAG,CAAC,IAAI,CAAC;AACjB,YAAY,CAAC,CAAC;AACd,YAAY,CAAC,CAAC;AACd,YAAY,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC;AACrD,YAAY,OAAO,CAAC,CAAC,CAAC,GAAG;AACzB,YAAY,aAAa,CAAC;AAC1B;AACA,QAAQ,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AACvB;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5C,YAAY,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3B,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC;AACzD,gBAAgB,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE;AAC9B,gBAAgB,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;AACpF,gBAAgB,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC1E,gBAAgB,WAAW,CAAC,CAAC,IAAI;AACjC,YAAY,CAAC,CAAC,EAAE;AAChB,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/D,YAAY,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,UAAU,CAAC,EAAE;AAC3D,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO;AACrD,QAAQ,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE;AACtD;AACA,QAAQ,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ;AACjF,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACtD,YAAY,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtJ,gBAAgB,aAAa,CAAC,CAAC,CAAC,GAAG;AACnC,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACpD,oBAAoB,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;AACzC,wBAAwB,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC;AACjE,wBAAwB,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE;AACtC,wBAAwB,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;AAC5F,wBAAwB,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAClF,wBAAwB,WAAW,CAAC,CAAC,IAAI;AACzC,oBAAoB,CAAC,CAAC,EAAE;AACxB,gBAAgB,CAAC;AACjB,gBAAgB,kBAAkB,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,EAAE;AAC/E,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC/B,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5C,QAAQ,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE;AAC1C,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;AACvG,KAAK,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;AAC3G,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpD,QAAQ,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE;AAC1C,QAAQ,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE;AAC7B,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,QAAQ,GAAG,CAAC,CAAC,CAAC;AACd,YAAY,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC;AACrD,YAAY,OAAO,CAAC,CAAC,CAAC,GAAG;AACzB;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5C,YAAY,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3B,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC;AACzD,gBAAgB,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE;AAC9B,gBAAgB,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;AACpF,gBAAgB,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC1E,gBAAgB,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE;AACpC,YAAY,CAAC,CAAC,EAAE;AAChB,QAAQ,CAAC;AACT;AACA,QAAQ,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE;AACtD;AACA,QAAQ,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC/B,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9C,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,2BAA2B,EAAE,KAAK,GAAG;AACtE;AACA,QAAQ,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,EAAE;AACpD,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC/C,QAAQ,KAAK,CAAC,eAAe,GAAG;AAChC,QAAQ,KAAK,CAAC,cAAc,GAAG;AAC/B,QAAQ,MAAM,CAAC,KAAK,CAAC;AACrB,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,QAAQ,KAAK,CAAC,eAAe,GAAG;AAChC,QAAQ,KAAK,CAAC,cAAc,GAAG;AAC/B,QAAQ,MAAM,CAAC,KAAK,CAAC;AACrB,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9C,QAAQ,GAAG,CAAC,MAAM,CAAC;AACnB;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzH,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC;AAClB,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AAChC,YAAY,IAAI,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE;AAC1C,YAAY,SAAS,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AACvC,YAAY,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE;AAClD,YAAY,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE;AAChC,QAAQ,EAAE;AACV;AACA,QAAQ,mBAAmB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AAC1D,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7C,QAAQ,GAAG,CAAC,MAAM,CAAC;AACnB;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzH,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC;AAClB,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AAChC,YAAY,IAAI,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE;AAC1C,YAAY,SAAS,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AACvC,YAAY,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE;AAClD,YAAY,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE;AAChC,QAAQ,EAAE;AACV;AACA,QAAQ,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACzD,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9C,QAAQ,GAAG,CAAC,MAAM,CAAC;AACnB;AACA,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC;AAClB,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AAChC,YAAY,IAAI,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE;AAC1C,YAAY,SAAS,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AACvC,YAAY,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE;AAClD,YAAY,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE;AAChC,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/E,YAAY,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE;AACjC,YAAY,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;AACnD,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACjK,YAAY,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACnC,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5C,QAAQ,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE;AAC1C,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;AACrG,KAAK,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;AAC3G,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpD,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AACxF,QAAQ,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtD,YAAY,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE;AAC9C,QAAQ,CAAC;AACT,QAAQ,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE;AAC7B,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,QAAQ,GAAG,CAAC,MAAM,CAAC;AACnB;AACA,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC;AAClB,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AAChC,YAAY,IAAI,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE;AAC1C,YAAY,SAAS,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AACvC,YAAY,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE;AAClD,YAAY,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE;AAChC,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7E,YAAY,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;AACnD,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9C,QAAQ,iBAAiB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE;AAC5C,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;AACrG,KAAK,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;AAC7G,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACtD,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AACxF,QAAQ,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtD,YAAY,iBAAiB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE;AAChD,QAAQ,CAAC;AACT,QAAQ,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE;AAC7B,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClD,QAAQ,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;AACjH,QAAQ,GAAG,CAAC,MAAM,CAAC;AACnB;AACA,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC;AAClB,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AAChC,YAAY,IAAI,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE;AAC1C,YAAY,SAAS,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AACvC,YAAY,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE;AAClD,YAAY,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE;AAChC,QAAQ,EAAE;AACV;AACA,QAAQ,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACzD,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,QAAQ,GAAG,CAAC,MAAM,CAAC;AACnB;AACA,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC;AAClB,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AAChC,YAAY,IAAI,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC;AACzC,QAAQ,EAAE;AACV;AACA,QAAQ,oBAAoB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AAC3D,IAAI,CAAC;AACL;AACA;AACA,+EAA+E;AAC/E,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ;AACrC,+EAA+E;AAC/E;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC,UAAU;AACtE,KAAK,CAAC,KAAK,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;AACxD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,MAAM;AAC9D,KAAK,CAAC,MAAM,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC;AACnC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC;AAChE,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,oBAAoB,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACzD;AACA,QAAQ,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AACxF,QAAQ,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK;AACvE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtD,YAAY,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,gBAAgB,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AACxC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;AACzC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACzB,QAAQ,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,QAAQ,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;AAC9C,QAAQ,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC;AAChD,QAAQ,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;AAC3C,QAAQ,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC;AAC7C;AACA,QAAQ,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE;AACxC,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC,UAAU;AACtE,KAAK,CAAC,KAAK,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;AAChE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,MAAM;AAC9D,KAAK,CAAC,MAAM,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC;AAChE,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,mBAAmB,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACxD,QAAQ,GAAG,CAAC,UAAU,CAAC;AACvB,YAAY,YAAY,CAAC;AACzB;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,YAAY,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE;AAC5D;AACA,YAAY,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO;AAC7J,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,gBAAgB,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,GAAG;AACvD,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACtC,oBAAoB,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9D,oBAAoB,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACzC,wBAAwB,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AACtD,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,GAAG;AAChD,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,UAAU,CAAC;AAC1B,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO;AAClD,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,QAAQ,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC,OAAO;AACvE,KAAK,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AACrD,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC7D,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE;AAClF,YAAY,CAAC,CAAC;AACd,YAAY,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACzC,YAAY,SAAS,CAAC;AACtB,YAAY,YAAY,CAAC;AACzB,YAAY,SAAS,CAAC;AACtB;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7C,YAAY,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;AACrC,YAAY,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE;AAC9D;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACjC,gBAAgB,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,EAAE;AAC3D,gBAAgB,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,gBAAgB,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC;AAC/D,gBAAgB,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,WAAW,CAAC;AACjE,gBAAgB,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC;AAC/D,gBAAgB,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC;AACjE;AACA,gBAAgB,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC;AACzC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI;AACvE,gBAAgB,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAC3C,gBAAgB,SAAS,CAAC,oBAAoB,CAAC,CAAC,CAAC,KAAK,CAAC;AACvD,gBAAgB,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/C,gBAAgB,oBAAoB,CAAC,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,EAAE;AAC9D,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,KAAK;AACpB,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACzC,gBAAgB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;AACjD,oBAAoB,CAAC;AACrB,wBAAwB,WAAW,CAAC,UAAU,OAAO,CAAC;AACtD,wBAAwB,WAAW,CAAC,UAAU,SAAS,CAAC,IAAI,CAAC;AAC7D,wBAAwB,QAAQ,CAAC,aAAa,0BAA0B,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AAClH,wBAAwB,OAAO,CAAC,cAAc,UAAU,CAAC,OAAO,CAAC;AACjE,wBAAwB,QAAQ,CAAC,aAAa,OAAO,CAAC,qBAAqB,GAAG;AAC9E,wBAAwB,oBAAoB,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC;AAC7E,wBAAwB,aAAa,CAAC,QAAQ,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;AACvE,wBAAwB,YAAY,CAAC,SAAS,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AACzE,wBAAwB,aAAa,CAAC,QAAQ,KAAK,CAAC;AACpD,wBAAwB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AACpD,wBAAwB,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AAC9D,oBAAoB,CAAC;AACrB,gBAAgB,EAAE;AAClB,gBAAgB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5C,oBAAoB,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO;AAClD,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,QAAQ,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC,OAAO;AACvE,KAAK,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AACrD,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC5D,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,2BAA2B,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE;AAC9E,YAAY,CAAC,CAAC;AACd,YAAY,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACzC,YAAY,SAAS,CAAC;AACtB,YAAY,YAAY,CAAC;AACzB,YAAY,SAAS,CAAC;AACtB;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7C,YAAY,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;AACrC,YAAY,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE;AAC9D;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACjC,gBAAgB,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AAClG,gBAAgB,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC9C,oBAAoB,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC;AACvD,oBAAoB,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC;AACnE,oBAAoB,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,WAAW,CAAC;AACrE,oBAAoB,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC;AACnE,oBAAoB,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC;AACrE,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,oBAAoB,mBAAmB,CAAC,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,EAAE;AACpE,gBAAgB,CAAC;AACjB;AACA,gBAAgB,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC;AACzC,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,IAAI;AACnB,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACxC,gBAAgB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;AAChD,oBAAoB,CAAC;AACrB,wBAAwB,WAAW,CAAC,UAAU,OAAO,CAAC;AACtD,wBAAwB,WAAW,CAAC,UAAU,SAAS,CAAC,IAAI,CAAC;AAC7D,wBAAwB,QAAQ,CAAC,aAAa,0BAA0B,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AAClH,wBAAwB,OAAO,CAAC,cAAc,UAAU,CAAC,OAAO,CAAC;AACjE,wBAAwB,QAAQ,CAAC,aAAa,OAAO,CAAC,qBAAqB,GAAG;AAC9E,wBAAwB,oBAAoB,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,oBAAoB,CAAC,CAAC,CAAC,KAAK,CAAC;AACvG,wBAAwB,aAAa,CAAC,QAAQ,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;AACvE,wBAAwB,YAAY,CAAC,SAAS,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AACzE,wBAAwB,aAAa,CAAC,QAAQ,KAAK,CAAC;AACpD,wBAAwB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AACpD,wBAAwB,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AAC9D,oBAAoB,CAAC;AACrB,gBAAgB,EAAE;AAClB;AACA,gBAAgB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5C,oBAAoB,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO;AAClD,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,QAAQ,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC,OAAO;AACvE,KAAK,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AACrD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa;AACpC,KAAK,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AACrJ,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;AACtI,KAAK,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;AAC9H,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AACtG,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AAC3E,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AAC5C,YAAY,SAAS,CAAC;AACtB,YAAY,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE;AAClF,YAAY,CAAC,CAAC;AACd,YAAY,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACzC,YAAY,SAAS,CAAC;AACtB,YAAY,YAAY,CAAC;AACzB;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,YAAY,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC/C,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChF,gBAAgB,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,oBAAoB,EAAE,CAAC,OAAO;AAC9B,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,GAAG;AAC1B,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,SAAS;AAChC,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;AAChC,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;AACnC,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;AAC7C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,GAAG,CAAC,MAAM;AACjC,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;AAC7C,gBAAgB,CAAC;AACjB,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,oBAAoB,EAAE,CAAC,OAAO;AAC9B,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,GAAG;AAC1B,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,SAAS;AAChC,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;AAChC,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;AACnC,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;AAC7C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,GAAG,CAAC,MAAM;AACjC,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;AAC7C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM;AAC7G,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;AACzE,QAAQ,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,gCAAgC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE;AAC3F,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACvD,YAAY,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO;AAClE,YAAY,aAAa,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO;AAC7F,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ;AACzE,QAAQ,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,YAAY,EAAE,CAAC,GAAG,CAAC,KAAK;AACxB,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;AACnD,gBAAgB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC;AAC3D,oBAAoB,CAAC;AACrB,wBAAwB,WAAW,CAAC,UAAU,OAAO,CAAC;AACtD,wBAAwB,WAAW,CAAC,UAAU,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;AAChE,wBAAwB,QAAQ,CAAC,aAAa,0BAA0B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AACrH,wBAAwB,MAAM,CAAC,eAAe,aAAa,CAAC;AAC5D,wBAAwB,OAAO,CAAC,cAAc,UAAU,CAAC,OAAO,CAAC;AACjE,wBAAwB,YAAY,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AAC5E,wBAAwB,aAAa,CAAC,QAAQ,KAAK,CAAC;AACpD,wBAAwB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AACpD,wBAAwB,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AAC9D,oBAAoB,CAAC;AACrB,gBAAgB,EAAE;AAClB,gBAAgB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5C,oBAAoB,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,KAAK,CAAC;AACzB,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7C,YAAY,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;AACrC,YAAY,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE;AAC9D;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACjC,gBAAgB,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,EAAE;AAC3D,gBAAgB,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,gBAAgB,YAAY,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC;AACzD,gBAAgB,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,gBAAgB,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC;AAC/D,gBAAgB,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC;AACjE,gBAAgB,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC;AAC/D,gBAAgB,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,WAAW,CAAC;AACjE,gBAAgB,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC;AAC/D,gBAAgB,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC;AACjE;AACA,gBAAgB,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC;AACzC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC;AAClI,gBAAgB,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1C,gBAAgB,SAAS,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC;AACtD,gBAAgB,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/C,gBAAgB,oBAAoB,CAAC,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,EAAE;AAC9D,YAAY,CAAC;AACb;AACA,YAAY,UAAU,CAAC,UAAU,GAAG;AACpC,YAAY,IAAI,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE;AAChE;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AAC1F,gBAAgB,EAAE,YAAY,CAAC,2BAA2B,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,EAAE;AAC1F,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,gBAAgB,EAAE,CAAC,KAAK;AACxB,gBAAgB,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AAC7C,oBAAoB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;AACrD,wBAAwB,CAAC;AACzB,4BAA4B,WAAW,CAAC,UAAU,OAAO,CAAC;AAC1D,4BAA4B,WAAW,CAAC,UAAU,SAAS,CAAC,IAAI,CAAC;AACjE,4BAA4B,QAAQ,CAAC,aAAa,0BAA0B,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AACtH,4BAA4B,OAAO,CAAC,cAAc,UAAU,CAAC,OAAO,CAAC;AACrE,4BAA4B,YAAY,CAAC,SAAS,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AAC7E,4BAA4B,aAAa,CAAC,QAAQ,KAAK,CAAC;AACxD,4BAA4B,oBAAoB,CAAC,CAAC,KAAK,CAAC;AACxD,4BAA4B,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AAClE,wBAAwB,CAAC;AACzB,oBAAoB,EAAE;AACtB,oBAAoB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,wBAAwB,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC/C,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,gBAAgB,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3E,oBAAoB,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK;AAC3C,oBAAoB,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,GAAG;AACjE,oBAAoB,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE;AACnK,oBAAoB,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE;AAC5K,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO;AAClD,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,QAAQ,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC,OAAO;AACvE,KAAK,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AACrD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa;AACpC,KAAK,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AACrJ,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;AACtI,KAAK,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;AAC9H,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AAC/G,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AACzE,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AAC5C,YAAY,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE;AAClF,YAAY,SAAS,CAAC;AACtB,YAAY,YAAY,CAAC;AACzB,YAAY,WAAW,CAAC;AACxB,YAAY,CAAC,CAAC;AACd,YAAY,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACzC,YAAY,SAAS,CAAC;AACtB,YAAY,YAAY,CAAC;AACzB,YAAY,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC;AACnC,YAAY,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC;AAChC,YAAY,KAAK,CAAC;AAClB;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,YAAY,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC/C,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChF,gBAAgB,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,oBAAoB,EAAE,CAAC,OAAO;AAC9B,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,GAAG;AAC1B,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,SAAS;AAChC,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;AAChC,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;AACnC,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;AAC7C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,GAAG,CAAC,MAAM;AACjC,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;AAC7C,gBAAgB,CAAC;AACjB,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,oBAAoB,EAAE,CAAC,OAAO;AAC9B,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,GAAG;AAC1B,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,SAAS;AAChC,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;AAChC,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;AACnC,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AAC9C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,EAAE,CAAC,GAAG,CAAC,MAAM;AACjC,oBAAoB,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AAC9C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ;AACzE,QAAQ,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,YAAY,EAAE,CAAC,GAAG,CAAC,OAAO;AAC1B,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC;AACrD,gBAAgB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,wBAAwB,CAAC;AAC7D,oBAAoB,CAAC;AACrB,wBAAwB,WAAW,CAAC,WAAW,OAAO,CAAC;AACvD,wBAAwB,WAAW,CAAC,WAAW,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;AACjE,wBAAwB,QAAQ,CAAC,cAAc,0BAA0B,CAAC,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE;AAClH,wBAAwB,MAAM,CAAC,gBAAgB,aAAa,CAAC;AAC7D,wBAAwB,OAAO,CAAC,eAAe,UAAU,CAAC,OAAO,CAAC;AAClE,wBAAwB,YAAY,CAAC,UAAU,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AAC7E,wBAAwB,aAAa,CAAC,SAAS,KAAK,CAAC;AACrD,wBAAwB,oBAAoB,CAAC,EAAE,KAAK,CAAC;AACrD,wBAAwB,QAAQ,CAAC,cAAc,OAAO,CAAC,QAAQ;AAC/D,oBAAoB,CAAC;AACrB,gBAAgB,EAAE;AAClB,gBAAgB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5C,oBAAoB,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI;AAClG,YAAY,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,2BAA2B,EAAE,KAAK,GAAG;AAC/E,YAAY,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI;AACpG,YAAY,aAAa,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,eAAe,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO;AACzF;AACA,YAAY,MAAM,CAAC,KAAK,CAAC;AACzB,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7C,YAAY,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;AACrC,YAAY,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE;AAC9D;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACjC,gBAAgB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO;AACpF,gBAAgB,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC9C,oBAAoB,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAClD,oBAAoB,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1C,oBAAoB,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AACvC,gBAAgB,CAAC;AACjB,gBAAgB,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC;AAC/D,gBAAgB,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,WAAW,CAAC;AACjE,gBAAgB,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC;AAC/D,gBAAgB,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC;AACjE,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AACpD,oBAAoB,mBAAmB,CAAC,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,EAAE;AACpE,gBAAgB,CAAC;AACjB;AACA,gBAAgB,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC;AACvD,gBAAgB,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,WAAW,CAAC;AACvD;AACA,gBAAgB,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACpC,oBAAoB,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO;AAC/I;AACA,oBAAoB,UAAU,CAAC,aAAa,GAAG;AAC/C,oBAAoB,IAAI,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE;AACxE;AACA,oBAAoB,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AAClG,wBAAwB,EAAE,YAAY,CAAC,2BAA2B,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,EAAE;AACxG,oBAAoB,CAAC;AACrB;AACA,oBAAoB,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtD;AACA,wBAAwB,EAAE,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AAC3D,wBAAwB,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AACvD,4BAA4B,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC;AAC/D,gCAAgC,CAAC;AACjC,oCAAoC,WAAW,CAAC,WAAW,OAAO,CAAC;AACnE,oCAAoC,WAAW,CAAC,WAAW,YAAY,CAAC,IAAI,CAAC;AAC7E,oCAAoC,QAAQ,CAAC,cAAc,0BAA0B,CAAC,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AACvH,oCAAoC,OAAO,CAAC,eAAe,UAAU,CAAC,OAAO,CAAC;AAC9E,oCAAoC,oBAAoB,CAAC,EAAE,YAAY,CAAC,oBAAoB,CAAC;AAC7F,oCAAoC,qBAAqB,CAAC,CAAC,YAAY,CAAC,aAAa,CAAC;AACtF,oCAAoC,YAAY,CAAC,UAAU,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AACzF,oCAAoC,aAAa,CAAC,SAAS,KAAK,CAAC;AACjE,oCAAoC,oBAAoB,CAAC,EAAE,KAAK,CAAC;AACjE,oCAAoC,QAAQ,CAAC,cAAc,OAAO,CAAC,QAAQ;AAC3E,gCAAgC,CAAC;AACjC,4BAA4B,EAAE;AAC9B,4BAA4B,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxD,gCAAgC,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACvD,4BAA4B,CAAC;AAC7B,wBAAwB,CAAC;AACzB;AACA,wBAAwB,EAAE,CAAC,IAAI,CAAC,GAAG;AACnC,wBAAwB,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrH,4BAA4B,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC;AAC/D,gCAAgC,CAAC;AACjC,oCAAoC,WAAW,CAAC,UAAU,OAAO,CAAC;AAClE,oCAAoC,WAAW,CAAC,UAAU,YAAY,CAAC,IAAI,CAAC;AAC5E,oCAAoC,QAAQ,CAAC,aAAa,0BAA0B,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AACjI,oCAAoC,KAAK,CAAC,gBAAgB,YAAY,CAAC,KAAK,CAAC;AAC7E,oCAAoC,SAAS,CAAC,YAAY,YAAY,CAAC,SAAS,CAAC;AACjF,oCAAoC,KAAK,CAAC,gBAAgB,KAAK,CAAC,QAAQ,CAAC;AACzE,oCAAoC,YAAY,CAAC,SAAS,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AACxF,oCAAoC,aAAa,CAAC,QAAQ,KAAK,CAAC;AAChE,oCAAoC,oBAAoB,CAAC,CAAC,KAAK,CAAC;AAChE,oCAAoC,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AAC1E,gCAAgC,CAAC;AACjC,4BAA4B,EAAE;AAC9B,4BAA4B,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxD,gCAAgC,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACvD,4BAA4B,CAAC;AAC7B,wBAAwB,CAAC;AACzB;AACA,wBAAwB,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK;AAC/C,wBAAwB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AAClH,4BAA4B,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE;AAC3G,4CAA4C,YAAY,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,kBAAkB,CAAC;AAC7H;AACA,4BAA4B,EAAE,CAAC,KAAK;AACpC,4BAA4B,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACzD,gCAAgC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;AACjE,oCAAoC,CAAC;AACrC,wCAAwC,WAAW,CAAC,UAAU,OAAO,CAAC;AACtE,wCAAwC,WAAW,CAAC,UAAU,YAAY,CAAC,IAAI,CAAC;AAChF,wCAAwC,QAAQ,CAAC,aAAa,0BAA0B,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AACrI,wCAAwC,KAAK,CAAC,gBAAgB,KAAK,CAAC;AACpE,wCAAwC,KAAK,CAAC,gBAAgB,KAAK,CAAC,QAAQ,CAAC;AAC7E,wCAAwC,YAAY,CAAC,SAAS,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AAC5F,wCAAwC,aAAa,CAAC,QAAQ,KAAK,CAAC;AACpE,wCAAwC,oBAAoB,CAAC,CAAC,KAAK,CAAC;AACpE,wCAAwC,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AAC9E,oCAAoC,CAAC;AACrC,gCAAgC,EAAE;AAClC,gCAAgC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5D,oCAAoC,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3D,gCAAgC,CAAC;AACjC,4BAA4B,CAAC;AAC7B;AACA,4BAA4B,EAAE,CAAC,MAAM,CAAC,KAAK;AAC3C,4BAA4B,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACrE,gCAAgC,UAAU,CAAC,MAAM,GAAG;AACpD,gCAAgC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,oCAAoC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC;AACzE,oCAAoC,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE;AAC5D,oCAAoC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACvF,wCAAwC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D,oCAAoC,EAAE,CAAC,OAAO,CAAC,qBAAqB,CAAC,EAAE;AACvE,oCAAoC,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE;AAC7D,gCAAgC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvE,oCAAoC,YAAY,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE;AAC7E,oCAAoC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,oCAAoC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;AAC9H,wCAAwC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC;AAC5E,4CAA4C,CAAC;AAC7C,gDAAgD,WAAW,CAAC,UAAU,OAAO,CAAC;AAC9E,gDAAgD,WAAW,CAAC,UAAU,YAAY,CAAC,IAAI,CAAC;AACxF,gDAAgD,QAAQ,CAAC,aAAa,0BAA0B,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AAC7I,gDAAgD,KAAK,CAAC,gBAAgB,KAAK,CAAC,QAAQ,CAAC;AACrF,gDAAgD,YAAY,CAAC,SAAS,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AACpG,gDAAgD,aAAa,CAAC,QAAQ,KAAK,CAAC;AAC5E,gDAAgD,oBAAoB,CAAC,CAAC,KAAK,CAAC;AAC5E,gDAAgD,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AACtF,4CAA4C,CAAC;AAC7C,wCAAwC,EAAE;AAC1C,wCAAwC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpE,4CAA4C,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACnE,wCAAwC,CAAC;AACzC,oCAAoC,CAAC;AACrC,oCAAoC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AACjE,gCAAgC,CAAC;AACjC,4BAA4B,CAAC;AAC7B,wBAAwB,CAAC;AACzB,oBAAoB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,wBAAwB,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACtF,4BAA4B,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK;AAC9C,4BAA4B,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,GAAG;AACzE,4BAA4B,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE;AAC3K,4BAA4B,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE;AACpL,wBAAwB,CAAC;AACzB,oBAAoB,CAAC;AACrB,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,oBAAoB,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO;AAC1F;AACA,oBAAoB,EAAE,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;AAC3D,oBAAoB,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AACnD,wBAAwB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC;AAC3D,4BAA4B,CAAC;AAC7B,gCAAgC,WAAW,CAAC,WAAW,OAAO,CAAC;AAC/D,gCAAgC,WAAW,CAAC,WAAW,YAAY,CAAC,IAAI,CAAC;AACzE,gCAAgC,QAAQ,CAAC,cAAc,0BAA0B,CAAC,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AACnH,gCAAgC,OAAO,CAAC,eAAe,UAAU,CAAC,OAAO,CAAC;AAC1E,gCAAgC,oBAAoB,CAAC,EAAE,YAAY,CAAC,oBAAoB,CAAC;AACzF,gCAAgC,qBAAqB,CAAC,CAAC,YAAY,CAAC,aAAa,CAAC;AAClF,gCAAgC,YAAY,CAAC,UAAU,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AACrF,gCAAgC,aAAa,CAAC,SAAS,KAAK,CAAC;AAC7D,gCAAgC,oBAAoB,CAAC,EAAE,KAAK,CAAC;AAC7D,gCAAgC,QAAQ,CAAC,cAAc,OAAO,CAAC,QAAQ;AACvE,4BAA4B,CAAC;AAC7B,wBAAwB,EAAE;AAC1B,wBAAwB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpD,4BAA4B,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACnD,wBAAwB,CAAC;AACzB,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,cAAc,CAAC;AAC9B,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;AACzH,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO;AAClD,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,QAAQ,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC,OAAO;AACvE,KAAK,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AACrD,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC5D,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AAC5C,YAAY,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE;AAClF,YAAY,CAAC,CAAC;AACd,YAAY,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACzC,YAAY,SAAS,CAAC;AACtB,YAAY,YAAY,CAAC;AACzB,YAAY,WAAW,CAAC;AACxB,YAAY,KAAK,CAAC;AAClB,YAAY,SAAS,CAAC;AACtB;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,YAAY,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC/C,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7C,YAAY,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;AACrC,YAAY,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE;AAC9D;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACjC,gBAAgB,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,EAAE;AAC3D,gBAAgB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,oBAAoB,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;AACjE,gBAAgB,CAAC;AACjB,gBAAgB,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC;AAC/D,gBAAgB,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,WAAW,CAAC;AACjE,gBAAgB,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC;AAC/D,gBAAgB,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC;AACjE,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC;AAClI,gBAAgB,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAC3C,gBAAgB,SAAS,CAAC,oBAAoB,CAAC,CAAC,CAAC,KAAK,CAAC;AACvD,gBAAgB,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/C,gBAAgB,oBAAoB,CAAC,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,EAAE;AAC9D,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;AAC5B,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,YAAY,YAAY,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE;AAChD,YAAY,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC1D,gBAAgB,iBAAiB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE;AACvE,YAAY,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;AACnC,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1C,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;AAC/E,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACxC,gBAAgB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;AAChD,oBAAoB,CAAC;AACrB,wBAAwB,WAAW,CAAC,UAAU,OAAO,CAAC;AACtD,wBAAwB,WAAW,CAAC,UAAU,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;AAChE,wBAAwB,QAAQ,CAAC,aAAa,0BAA0B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AACrH,wBAAwB,OAAO,CAAC,cAAc,UAAU,CAAC,OAAO,CAAC;AACjE,wBAAwB,YAAY,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AAC5E,wBAAwB,aAAa,CAAC,QAAQ,KAAK,CAAC;AACpD,wBAAwB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AACpD,wBAAwB,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AAC9D,oBAAoB,CAAC;AACrB,gBAAgB,EAAE;AAClB,gBAAgB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5C,oBAAoB,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;AAC/B,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACxC,gBAAgB,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE;AACzD,gBAAgB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;AAChD,oBAAoB,CAAC;AACrB,wBAAwB,WAAW,CAAC,UAAU,OAAO,CAAC;AACtD,wBAAwB,WAAW,CAAC,UAAU,YAAY,CAAC,IAAI,CAAC;AAChE,wBAAwB,QAAQ,CAAC,aAAa,0BAA0B,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AACrH,wBAAwB,OAAO,CAAC,cAAc,UAAU,CAAC,OAAO,CAAC;AACjE,wBAAwB,YAAY,CAAC,SAAS,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AAC5E,wBAAwB,aAAa,CAAC,QAAQ,KAAK,CAAC;AACpD,wBAAwB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AACpD,wBAAwB,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AAC9D,oBAAoB,CAAC;AACrB,gBAAgB,EAAE;AAClB,gBAAgB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5C,oBAAoB,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,IAAI;AACnB,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACxC,gBAAgB,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE;AACzD,gBAAgB,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE;AAC9E,gBAAgB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;AAChD,oBAAoB,CAAC;AACrB,wBAAwB,WAAW,CAAC,UAAU,OAAO,CAAC;AACtD,wBAAwB,WAAW,CAAC,UAAU,YAAY,CAAC,IAAI,CAAC;AAChE,wBAAwB,QAAQ,CAAC,aAAa,0BAA0B,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AACrH,wBAAwB,OAAO,CAAC,cAAc,UAAU,CAAC,OAAO,CAAC;AACjE,wBAAwB,KAAK,CAAC,gBAAgB,KAAK,CAAC;AACpD,wBAAwB,KAAK,CAAC,gBAAgB,YAAY,CAAC,KAAK,CAAC;AACjE,wBAAwB,SAAS,CAAC,YAAY,YAAY,CAAC,SAAS,CAAC;AACrE,wBAAwB,KAAK,CAAC,gBAAgB,KAAK,CAAC,QAAQ,CAAC;AAC7D,wBAAwB,YAAY,CAAC,SAAS,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AAC5E,wBAAwB,aAAa,CAAC,QAAQ,KAAK,CAAC;AACpD,wBAAwB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AACpD,wBAAwB,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AAC9D,oBAAoB,CAAC;AACrB,gBAAgB,EAAE;AAClB,gBAAgB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5C,oBAAoB,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AAC5C,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACxC,gBAAgB,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,GAAG;AACnD,gBAAgB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;AAChD,oBAAoB,CAAC;AACrB,wBAAwB,WAAW,CAAC,UAAU,OAAO,CAAC;AACtD,wBAAwB,WAAW,CAAC,UAAU,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;AACpE,wBAAwB,QAAQ,CAAC,aAAa,0BAA0B,CAAC,CAAC,cAAc,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AACxK,wBAAwB,OAAO,CAAC,cAAc,UAAU,CAAC,OAAO,CAAC;AACjE,wBAAwB,YAAY,CAAC,SAAS,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AAChF,wBAAwB,aAAa,CAAC,QAAQ,KAAK,CAAC;AACpD,wBAAwB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AACpD,wBAAwB,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AAC9D,oBAAoB,CAAC;AACrB,gBAAgB,EAAE;AAClB,gBAAgB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5C,oBAAoB,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,KAAK;AACpB,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1E,gBAAgB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE;AAClH,gBAAgB,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAC3D,oBAAoB,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC;AACvE,oBAAoB,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC;AACtD,oBAAoB,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC;AAC3E,oBAAoB,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE;AACjJ,oBAAoB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;AACrD,wBAAwB,CAAC;AACzB,4BAA4B,WAAW,CAAC,UAAU,OAAO,CAAC;AAC1D,4BAA4B,WAAW,CAAC,UAAU,CAAC,KAAK,EAAE;AAC1D,4BAA4B,aAAa,CAAC,QAAQ,QAAQ,CAAC,YAAY,CAAC;AACxE,4BAA4B,UAAU,CAAC,WAAW,0BAA0B,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AAC1H,4BAA4B,MAAM,CAAC,eAAe,0BAA0B,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AAC7H,4BAA4B,YAAY,CAAC,SAAS,QAAQ,CAAC,aAAa,CAAC;AACzE,4BAA4B,QAAQ,CAAC,aAAa,QAAQ,CAAC,gBAAgB,CAAC;AAC5E,4BAA4B,KAAK,CAAC,gBAAgB,KAAK,CAAC,QAAQ,CAAC;AACjE,4BAA4B,aAAa,CAAC,QAAQ,KAAK,CAAC;AACxD,4BAA4B,oBAAoB,CAAC,CAAC,KAAK,CAAC;AACxD,4BAA4B,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AAClE,wBAAwB,CAAC;AACzB,oBAAoB,EAAE;AACtB,oBAAoB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,wBAAwB,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC/C,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO;AAClD,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,QAAQ,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC,OAAO;AACvE,KAAK,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AACrD,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,oBAAoB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC9D,QAAQ,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;AACvD,QAAQ,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE;AACtD,IAAI,CAAC;AACL;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC,CAAC,iBAAiB,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC3E,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACpC,YAAY,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;AAClC,gBAAgB,WAAW,CAAC,UAAU,OAAO,CAAC;AAC9C,gBAAgB,WAAW,CAAC,UAAU,WAAW,CAAC;AAClD,gBAAgB,QAAQ,CAAC,aAAa,gBAAgB,CAAC,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AAC7F,gBAAgB,OAAO,CAAC,cAAc,OAAO,CAAC,2BAA2B,CAAC,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;AACjG,gBAAgB,YAAY,CAAC,SAAS,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AAC9D,gBAAgB,aAAa,CAAC,QAAQ,iBAAiB,CAAC;AACxD,gBAAgB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AAC5C,gBAAgB,QAAQ,CAAC,aAAa,OAAO,CAAC,QAAQ;AACtD,YAAY,CAAC,CAAC,EAAE;AAChB,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AACjD,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU;AACnC,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,EAAE;AACP,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAClC,QAAQ,GAAG,CAAC,CAAC;AACb,YAAY,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC;AAC9C,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT,IAAI,KAAK;AACT;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AAC1F,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACvC,QAAQ,GAAG,CAAC,CAAC;AACb,YAAY,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC;AACzE,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,KAAK,CAAC;AACzB,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,EAAE,aAAa,GAAG;;AC7yGlB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO;AAC1B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,GAAG;AACH,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC;AACxE,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;AACrD,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa;AACxB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACjB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI;AAC1B,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC9B,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS;AAC/B,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AACjC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY;AAClC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC9B,CAAC,EAAE;AACH,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;AACnB,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;AACZ,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC;AAChB,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC;AACjB,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC;AACpB,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC;AACnB,IAAI,QAAQ,CAAC,CAAC,CAAC;AACf,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO;AACjB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI;AACzF,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG;AAC9E,CAAC,CAAC,CAAC,OAAO,CAAC;AACX,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;AAClF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;AACnG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO;AACvH,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;AAC9B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE;AAClH,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS;AAC7B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ;AACnG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC;AAC5E,CAAC,EAAE;AACH,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACtD,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;AACpC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE;AACpC,IAAI,CAAC;AACL,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AACjH,wBAAwB,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AACnE,wBAAwB,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,GAAG;AACzG,SAAS,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE;AACrC,IAAI,CAAC;AACL,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC;AAC7G,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;AACzD,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ;AACjC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC;AACvC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;AACxF,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE;AAClG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AAChC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC;AACvC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC;AAC9B,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;AAC7D,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,MAAM;AACnD,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC;AACvC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACrC,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC;AACxC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS;AAClC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC;AACvC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC;AAChC,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AACzD,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AAChC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC;AACvC,KAAK,EAAE;AACP,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACpD,QAAQ,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AACxD,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;AACjD,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;AACvG,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;AAC5G,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACnH,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AAChH,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AAC1C,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AAC3C;AACA,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;AACjD,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AACvC,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AACxC,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AAC3C,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AAC1C,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AACxD,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE;AACpD,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpD,YAAY,EAAE,CAAC,GAAG,CAAC,GAAG;AACtB,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AAC1E,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AAC7C;AACA,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AAClC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,EAAE;AACxD,aAAa,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AAC5D,YAAY,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC;AACxC,gBAAgB,IAAI,CAAC,OAAO,CAAC;AAC7B,gBAAgB,IAAI,CAAC,SAAS,CAAC,UAAU;AACzC,YAAY,EAAE;AACd,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AACvD,QAAQ,CAAC;AACT,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AAC3C,IAAI,CAAC;AACL,EAAE;AACF;AACA,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;AAC7C,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACvB;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;AAC9C,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,EAAE;AACP,IAAI,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACzB,QAAQ,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AACjD,QAAQ,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AACnD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC;AACtD,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AACnE,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC3B,QAAQ,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE;AACpD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AAC7C,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC;AACtE,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACrC,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;AAC9C,YAAY,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACpF,YAAY,CAAC,IAAI,EAAE;AACnB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;AAC9C,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC;AACrE,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACrC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9E,YAAY,EAAE,iBAAiB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/D,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,iBAAiB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/D,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,EAAE;AACF;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;ACxMpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW;AAC9B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW;AACzB,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC;AACxH,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,EAAE;AACP,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE;AACxC,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,UAAU,GAAG;AAC5E,YAAY,MAAM,CAAC;AACnB,YAAY,CAAC,CAAC;AACd;AACA,QAAQ,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/B,YAAY,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE;AACrF,YAAY,SAAS,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AACrD,YAAY,QAAQ,CAAC,CAAC,EAAE;AACxB,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE;AACrB;AACA,QAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI;AAC7E,QAAQ,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;AAC1B,QAAQ,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC9C,YAAY,MAAM,CAAC,KAAK,CAAC;AACzB,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AAC3B,YAAY,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AACxD,YAAY,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;AACvD,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;AACrD,YAAY,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AAChD,YAAY,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AACjD,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;AAC9C,YAAY,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;AAClC,YAAY,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AACpE,YAAY,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;AAChE,YAAY,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;AAC1C,gBAAgB,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AAC3D,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;AAC3C,gBAAgB,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AAC5D,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;AACzC,gBAAgB,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AAC1D,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;AAC5C,gBAAgB,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AAC7D,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;AAC5D,QAAQ,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;AAC7D,QAAQ,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE;AAChE,QAAQ,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;AAC/D,IAAI,EAAE;AACN;AACA,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE;AACrD,IAAI,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC/B;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,EAAE;AACX,QAAQ,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AAC1D,YAAY,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AAC9C,YAAY,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3B;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,gBAAgB,MAAM,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO;AACxE,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC9C,gBAAgB,IAAI,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC;AAC/C,oBAAoB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;AACjD,oBAAoB,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;AACxD,oBAAoB,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AACvD,oBAAoB,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AACrD,oBAAoB,KAAK,CAAC;AAC1B,gBAAgB,IAAI,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC;AAClD,oBAAoB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;AACpD,oBAAoB,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;AACxD,oBAAoB,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AACvD,oBAAoB,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AACxD,oBAAoB,KAAK,CAAC;AAC1B,gBAAgB,IAAI,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC;AACjD,oBAAoB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;AACnD,oBAAoB,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;AACxD,oBAAoB,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AACtD,oBAAoB,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AACxD,oBAAoB,KAAK,CAAC;AAC1B,gBAAgB,IAAI,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC;AAC9C,oBAAoB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;AAChD,oBAAoB,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;AACxD,oBAAoB,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AACtD,oBAAoB,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AACrD,oBAAoB,KAAK,CAAC;AAC1B,gBAAgB,IAAI,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC;AAC9C,oBAAoB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AACzC,oBAAoB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AACjD,oBAAoB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AAClD,oBAAoB,KAAK,CAAC;AAC1B,gBAAgB,OAAO,CAAC;AACxB,gBAAgB,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC;AAC1C,oBAAoB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AACzC,oBAAoB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AACjD,oBAAoB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AAClD,oBAAoB,KAAK,CAAC;AAC1B,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;AAC/B,gBAAgB,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,CAAC;AAC7D,YAAY,EAAE;AACd,YAAY,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE;AACnD,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC;AACzD,SAAS,EAAE;AACX,QAAQ,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC7C,YAAY,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AAC9C,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE;AACrD;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,gBAAgB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,GAAG;AAC7C,gBAAgB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC7C,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC;AACzD,SAAS,EAAE;AACX,QAAQ,aAAa,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACpC,YAAY,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,gBAAgB,IAAI,CAAC,QAAQ,CAAC,GAAG,GAAG,OAAO,GAAG;AAC9C,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AAC5B,SAAS,EAAE;AACX,QAAQ,kBAAkB,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACzC,YAAY,GAAG,CAAC,CAAC,CAAC;AAClB;AACA,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/D,gBAAgB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;AACvD,oBAAoB,MAAM,CAAC,IAAI,CAAC;AAChC,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,KAAK,CAAC;AACzB,QAAQ,EAAE;AACV;AACA;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC;AACzD,SAAS,EAAE;AACX,QAAQ,kBAAkB,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACjD,YAAY,GAAG,CAAC,CAAC,CAAC;AAClB;AACA,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/D,gBAAgB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AACzD,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT;AACA,IAAI,EAAE;AACN;AACA;AACA,IAAI,+EAA+E;AACnF,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO;AACtB,IAAI,+EAA+E;AACnF,IAAI,QAAQ,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC/C,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;AACrC,YAAY,CAAC,CAAC;AACd;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACtD,YAAY,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACrD,gBAAgB,MAAM,CAAC,CAAC,CAAC;AACzB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC;AAClB,IAAI,CAAC;AACL;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;ACpOpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,GAAG,CAAC,CAAC;AACd;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC;AACxD,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS;AACxB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,CAAC,CAAC,CAAC,MAAM;AACd,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,MAAM;AACjD,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,QAAQ;AACnD,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,GAAG;AAC9C,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,SAAS;AACpD,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,KAAK;AAChD,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,YAAY;AACvD,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,MAAM;AACjD,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,WAAW;AACtD,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,IAAI;AAC/C,KAAK,EAAE;AACP,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE;AAClC,QAAQ,MAAM,CAAC,OAAO,CAAC,CAAC;AACxB,QAAQ,QAAQ,CAAC,KAAK,CAAC,CAAC;AACxB,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC;AACxB,QAAQ,SAAS,CAAC,IAAI,CAAC,CAAC;AACxB,QAAQ,KAAK,CAAC,QAAQ,CAAC,CAAC;AACxB,QAAQ,YAAY,CAAC,CAAC,CAAC,CAAC;AACxB,QAAQ,MAAM,CAAC,OAAO,CAAC,CAAC;AACxB,QAAQ,WAAW,CAAC,EAAE,CAAC,CAAC;AACxB,QAAQ,IAAI,CAAC,SAAS,CAAC,CAAC;AACxB,QAAQ,UAAU,CAAC,CAAC,CAAC;AACrB,YAAY,CAAC,CAAC,CAAC,CAAC;AAChB,gBAAgB,MAAM,CAAC,CAAC,KAAK,CAAC;AAC9B,gBAAgB,sBAAsB,CAAC,CAAC,IAAI,CAAC;AAC7C,gBAAgB,OAAO,CAAC,CAAC,KAAK,CAAC;AAC/B,gBAAgB,KAAK,CAAC,CAAC,KAAK,CAAC;AAC7B,gBAAgB,oBAAoB,CAAC,CAAC,IAAI,CAAC;AAC3C,gBAAgB,QAAQ,CAAC,CAAC,KAAK;AAC/B,YAAY,EAAE;AACd,YAAY,CAAC,CAAC,CAAC,CAAC;AAChB,gBAAgB,MAAM,CAAC,CAAC,IAAI,CAAC;AAC7B,gBAAgB,sBAAsB,CAAC,CAAC,KAAK,CAAC;AAC9C,gBAAgB,OAAO,CAAC,CAAC,KAAK,CAAC;AAC/B,gBAAgB,KAAK,CAAC,CAAC,IAAI,CAAC;AAC5B,gBAAgB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AAC5C,gBAAgB,QAAQ,CAAC,CAAC,KAAK;AAC/B,YAAY,EAAE;AACd,YAAY,CAAC,CAAC,CAAC,CAAC;AAChB,gBAAgB,MAAM,CAAC,CAAC,KAAK,CAAC;AAC9B,gBAAgB,sBAAsB,CAAC,CAAC,IAAI,CAAC;AAC7C,gBAAgB,OAAO,CAAC,CAAC,KAAK,CAAC;AAC/B,gBAAgB,KAAK,CAAC,CAAC,IAAI,CAAC;AAC5B,gBAAgB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AAC5C,gBAAgB,QAAQ,CAAC,CAAC,KAAK;AAC/B,YAAY,EAAE;AACd,YAAY,CAAC,CAAC,CAAC,CAAC;AAChB,gBAAgB,MAAM,CAAC,CAAC,KAAK,CAAC;AAC9B,gBAAgB,sBAAsB,CAAC,CAAC,KAAK,CAAC;AAC9C,gBAAgB,OAAO,CAAC,CAAC,IAAI,CAAC;AAC9B,gBAAgB,KAAK,CAAC,CAAC,IAAI,CAAC;AAC5B,gBAAgB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AAC5C,gBAAgB,QAAQ,CAAC,CAAC,KAAK;AAC/B,YAAY,EAAE;AACd,YAAY,CAAC,CAAC,CAAC,CAAC;AAChB,gBAAgB,MAAM,CAAC,CAAC,KAAK,CAAC;AAC9B,gBAAgB,sBAAsB,CAAC,CAAC,KAAK,CAAC;AAC9C,gBAAgB,OAAO,CAAC,CAAC,IAAI,CAAC;AAC9B,gBAAgB,KAAK,CAAC,CAAC,KAAK,CAAC;AAC7B,gBAAgB,oBAAoB,CAAC,CAAC,IAAI,CAAC;AAC3C,gBAAgB,QAAQ,CAAC,CAAC,KAAK;AAC/B,YAAY,EAAE;AACd,YAAY,CAAC,CAAC,CAAC,CAAC;AAChB,gBAAgB,MAAM,CAAC,CAAC,KAAK,CAAC;AAC9B,gBAAgB,sBAAsB,CAAC,CAAC,KAAK,CAAC;AAC9C,gBAAgB,OAAO,CAAC,CAAC,IAAI,CAAC;AAC9B,gBAAgB,KAAK,CAAC,CAAC,KAAK,CAAC;AAC7B,gBAAgB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AAC5C,gBAAgB,QAAQ,CAAC,CAAC,IAAI;AAC9B,YAAY,EAAE;AACd,YAAY,CAAC,CAAC,CAAC,CAAC;AAChB,gBAAgB,MAAM,CAAC,CAAC,KAAK,CAAC;AAC9B,gBAAgB,sBAAsB,CAAC,CAAC,IAAI,CAAC;AAC7C,gBAAgB,OAAO,CAAC,CAAC,KAAK,CAAC;AAC/B,gBAAgB,KAAK,CAAC,CAAC,KAAK,CAAC;AAC7B,gBAAgB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AAC5C,gBAAgB,QAAQ,CAAC,CAAC,IAAI;AAC9B,YAAY,EAAE;AACd,YAAY,CAAC,CAAC,CAAC,CAAC;AAChB,gBAAgB,MAAM,CAAC,CAAC,IAAI,CAAC;AAC7B,gBAAgB,sBAAsB,CAAC,CAAC,KAAK,CAAC;AAC9C,gBAAgB,OAAO,CAAC,CAAC,KAAK,CAAC;AAC/B,gBAAgB,KAAK,CAAC,CAAC,KAAK,CAAC;AAC7B,gBAAgB,oBAAoB,CAAC,CAAC,KAAK,CAAC;AAC5C,gBAAgB,QAAQ,CAAC,CAAC,IAAI;AAC9B,YAAY,EAAE;AACd,YAAY,CAAC,CAAC,CAAC,CAAC;AAChB,gBAAgB,MAAM,CAAC,CAAC,IAAI,CAAC;AAC7B,gBAAgB,sBAAsB,CAAC,CAAC,KAAK,CAAC;AAC9C,gBAAgB,OAAO,CAAC,CAAC,KAAK,CAAC;AAC/B,gBAAgB,KAAK,CAAC,CAAC,KAAK,CAAC;AAC7B,gBAAgB,oBAAoB,CAAC,CAAC,IAAI,CAAC;AAC3C,gBAAgB,QAAQ,CAAC,CAAC,KAAK;AAC/B,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,GAAG;AACP;AACA,EAAE,aAAa,GAAG;;ACzIlB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM;AACzB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU;AAC7C,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG;AACd,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACjB;AACA,GAAG;AACH,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;AAC1E,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACP,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK;AACnE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,EAAE,CAAC;AAC1E,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACP,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW;AAC7E,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;AAC9E,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACP,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;AAC9D,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACP,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,OAAO,IAAI,IAAI,GAAG,EAAE,CAAC;AACxE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,IAAI,IAAI,GAAG,EAAE,CAAC;AAC7D,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACR,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC;AAClD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,WAAW;AACrC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,WAAW;AACrC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;AAC3D,CAAC,CAAC;AACF,CAAC,GAAG;AACJ,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAChC;AACA,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,SAAS,CAAC;AAC1B,QAAQ,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACrB,QAAQ,CAAC,CAAC;AACV;AACA;AACA,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI;AACrE,IAAI,EAAE,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ;AAC9D,IAAI,EAAE,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AACtC,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC;AACnB,YAAY,EAAE,CAAC,iBAAiB,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;AAC1C,YAAY,OAAO,CAAC,YAAY,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACxE,YAAY,SAAS,CAAC,UAAU,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACxE,YAAY,QAAQ,CAAC,WAAW,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACxE,YAAY,QAAQ,CAAC,WAAW,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;AACvE,QAAQ,EAAE;AACV,IAAI,CAAC;AACL;AACA,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU;AACnE,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ;AACpE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM;AAC/C,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;AAC1B,QAAQ,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;AAClD,QAAQ,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9B,IAAI,CAAC;AACL;AACA,IAAI,EAAE,MAAM,CAAC,UAAU;AACvB,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ;AAC1D,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3B;AACA,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW;AAC5C,QAAQ,EAAE,CAAC,aAAa,OAAO,CAAC,EAAE,CAAC;AACnC,QAAQ,IAAI,CAAC,WAAW,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,GAAG;AACnD,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,EAAE;AACnG,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AACvC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AAC1C,SAAS,EAAE;AACX,QAAQ,WAAW,CAAC,IAAI,CAAC,CAAC;AAC1B;AACA,QAAQ,EAAE,GAAG,CAAC,KAAK;AACnB,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;AAC7F,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AACpC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AAC1C,SAAS,EAAE;AACX,QAAQ,OAAO,CAAC,QAAQ,IAAI,CAAC;AAC7B,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,WAAW,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,CAAC;AACnI,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,OAAO,EAAE;AACjE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS;AACtC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AAC1C,SAAS,EAAE;AACX,QAAQ,SAAS,CAAC,MAAM,IAAI,CAAC;AAC7B,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC;AAClH,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,EAAE;AACnE,SAAS,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,mBAAmB,GAAG,EAAE,EAAE,EAAE,CAAC;AACzF,SAAS,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;AACvE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AAC1C,SAAS,EAAE;AACX,QAAQ,MAAM,CAAC,SAAS,IAAI,CAAC;AAC7B;AACA,QAAQ,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AAC7E,QAAQ,QAAQ,CAAC,WAAW,GAAG;AAC/B,QAAQ,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AAChE,QAAQ,iBAAiB,CAAC,EAAE,IAAI,CAAC;AACjC;AACA,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,UAAU;AAClC,QAAQ,YAAY,CAAC,GAAG,GAAG;AAC3B;AACA,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK;AAC/E,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS;AAC9E,QAAQ,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI;AAC5E,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS;AAC1E,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK;AAC7E,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC;AACpE,QAAQ,cAAc,CAAC,CAAC,GAAG;AAC3B;AACA,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO;AACvE,QAAQ,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI;AAC1E,QAAQ,MAAM,CAAC,SAAS,IAAI,CAAC;AAC7B,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;AACxF,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,MAAM;AAChD,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AAC1C,SAAS,EAAE;AACX,QAAQ,MAAM,CAAC,aAAa,IAAI,CAAC;AACjC,QAAQ,KAAK,CAAC,cAAc,IAAI,CAAC;AACjC,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;AACnH,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,QAAQ;AACpD,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AAC1C,SAAS,EAAE;AACX,QAAQ,QAAQ,CAAC,OAAO,IAAI,CAAC;AAC7B,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,SAAS;AACtD,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AAC1C,SAAS,EAAE;AACX,QAAQ,SAAS,CAAC,MAAM,IAAI,CAAC;AAC7B;AACA,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACtE,QAAQ,EAAE,YAAY,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK;AACjD,QAAQ,kBAAkB,CAAC,KAAK,IAAI,CAAC;AACrC,QAAQ,gBAAgB,CAAC,OAAO,IAAI,CAAC;AACrC;AACA,QAAQ,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS;AAC5B,QAAQ,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ;AAC5C,QAAQ,SAAS,CAAC,MAAM,IAAI,CAAC;AAC7B;AACA,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,QAAQ;AACnC,QAAQ,OAAO,CAAC,QAAQ,IAAI,CAAC;AAC7B;AACA,QAAQ,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;AACnD,QAAQ,QAAQ,CAAC,OAAO,IAAI;AAC5B;AACA,IAAI,EAAE,CAAC,EAAE,gBAAgB,CAAC,CAAC,OAAO,CAAC,EAAE;AACrC;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C,QAAQ,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI;AACpG,IAAI,CAAC;AACL,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,QAAQ,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS;AACjF,QAAQ,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC9E,QAAQ,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI;AACxE,IAAI,CAAC;AACL;AACA,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,UAAU;AAC9B,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzB,QAAQ,CAAC,aAAa,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACjD,QAAQ,CAAC,iBAAiB,EAAE,CAAC,IAAI,CAAC;AAClC,QAAQ,CAAC,SAAS,EAAE,SAAS,KAAK,CAAC;AACnC,QAAQ,CAAC,WAAW,EAAE,OAAO,KAAK,CAAC;AACnC,QAAQ,CAAC,WAAW,EAAE,OAAO,KAAK,CAAC;AACnC,QAAQ,CAAC,KAAK,EAAE,aAAa,IAAI,CAAC;AAClC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO;AACpD,QAAQ,CAAC,OAAO,EAAE,WAAW,KAAK,CAAC;AACnC,QAAQ,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE;AACxD,QAAQ,CAAC,UAAU,EAAE,QAAQ,IAAI,CAAC;AAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,QAAQ,CAAC,QAAQ,EAAE,UAAU,KAAK,CAAC;AACnC,QAAQ,CAAC,kBAAkB,EAAE,CAAC,IAAI;AAClC,IAAI,EAAE;AACN;AACA,IAAI,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3B,IAAI,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG;AACzB,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG;AAC9B;AACA,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO;AAClH;AACA,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU;AAC3C,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/B;AACA,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxD,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE;AACtF,QAAQ,KAAK,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,EAAE;AAClC,IAAI,GAAG;AACP;AACA,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE;AACxC;AACA,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO;AAC5B,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AACvB,QAAQ,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM;AAC/E,QAAQ,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AAC5C,IAAI,CAAC;AACL;AACA,IAAI,IAAI,CAAC,OAAO,cAAc,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE;AACnF,IAAI,IAAI,CAAC,MAAM,eAAe,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAC9D;AACA,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,EAAE;AACnD,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACvB,QAAQ,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG;AAChC,QAAQ,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG;AAChC,QAAQ,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE;AAClC,QAAQ,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;AACpC,QAAQ,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE;AAC/B,QAAQ,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE;AAC/B,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG;AAC1B,IAAI,EAAE,yBAAyB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;AAC/C,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAClC,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE;AACvF,IAAI,CAAC;AACL;AACA,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC,KAAK;AACjF,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,SAAS,EAAE;AACzD,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACvB,QAAQ,KAAK,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG;AACjC,QAAQ,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG;AACjC,QAAQ,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE;AACrC,QAAQ,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE;AACnC,QAAQ,KAAK,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE;AAChC,QAAQ,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE;AAChC,QAAQ,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO;AAC/D,IAAI,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG;AAC/B;AACA,IAAI,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE;AAC1E,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;AAC/C;AACA,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI;AACrE,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM;AACjE,IAAI,EAAE,MAAM,SAAS,CAAC;AACtB,IAAI,IAAI,CAAC,SAAS,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;AACpD,IAAI,IAAI,CAAC,UAAU,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;AACrD,IAAI,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;AACvD,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,QAAQ,CAAC;AAClE;AACA,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,YAAY,EAAE;AAC5C,QAAQ,OAAO,CAAC,kBAAkB,IAAI,CAAC,MAAM,CAAC;AAC9C,QAAQ,aAAa,CAAC,YAAY,CAAC,IAAI,CAAC,eAAe,CAAC;AACxD,QAAQ,kBAAkB,CAAC,OAAO,IAAI,CAAC,kBAAkB,CAAC;AAC1D,QAAQ,kBAAkB,CAAC,OAAO,IAAI,CAAC,kBAAkB,CAAC;AAC1D,QAAQ,qBAAqB,CAAC,IAAI,IAAI,CAAC,qBAAqB,CAAC;AAC7D,QAAQ,qBAAqB,CAAC,IAAI,IAAI,CAAC,qBAAqB,CAAC;AAC7D,QAAQ,cAAc,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,EAAE;AACtE,QAAQ,UAAU,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,gBAAgB,CAAC,EAAE;AACvE,QAAQ,YAAY,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,EAAE;AACpE,QAAQ,eAAe,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,gBAAgB,CAAC,EAAE;AACvE,QAAQ,WAAW,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,EAAE;AACnE,QAAQ,cAAc,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,EAAE;AACtE,QAAQ,YAAY,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,EAAE;AACpE,QAAQ,WAAW,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,EAAE;AACnE,QAAQ,YAAY,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,EAAE;AACpE,QAAQ,cAAc,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,EAAE;AACtE,QAAQ,sBAAsB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,uBAAuB,CAAC,EAAE;AAC9E,QAAQ,wBAAwB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,yBAAyB,CAAC,EAAE;AAChF,QAAQ,aAAa,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,EAAE;AACrE,QAAQ,YAAY,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,CAAC;AACnE,IAAI,GAAG;AACP;AACA,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,YAAY,EAAE;AAC5C,QAAQ,OAAO,CAAC,eAAe,IAAI,CAAC,SAAS,CAAC;AAC9C,QAAQ,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,eAAe,CAAC;AACrD,QAAQ,kBAAkB,CAAC,IAAI,IAAI,CAAC,kBAAkB,CAAC;AACvD,QAAQ,kBAAkB,CAAC,IAAI,IAAI,CAAC,kBAAkB,CAAC;AACvD,QAAQ,qBAAqB,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC;AAC1D,QAAQ,qBAAqB,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC;AAC1D,QAAQ,YAAY,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,gBAAgB,CAAC,EAAE;AACpE,QAAQ,WAAW,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,CAAC;AAClE,IAAI,GAAG;AACP;AACA,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AACvB,QAAQ,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG;AACpE,IAAI,CAAC;AACL;AACA,IAAI,IAAI,CAAC,oBAAoB,GAAG;AAChC;AACA,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;AAC7E;AACA,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK;AACvB,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE;AAC9B,QAAQ,MAAM,CAAC,CAAC,IAAI;AACpB,IAAI,GAAG;AACP;AACA,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AACvD,QAAQ,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ;AACvE,QAAQ,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC;AACvD;AACA,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9C;AACA,QAAQ,EAAE,CAAC,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACtC,YAAY,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,EAAE;AAC1E,QAAQ,CAAC;AACT,IAAI,GAAG;AACP;AACA,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1D,QAAQ,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ;AACvE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC;AACzC,YAAY,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC;AAC3D,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAChC,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9C,IAAI,GAAG;AACP;AACA,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAC7D,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC7B,YAAY,KAAK,CAAC,QAAQ,CAAC,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,IAAI;AAC1G,QAAQ,CAAC;AACT,IAAI,GAAG;AACP;AACA,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAChE,QAAQ,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ;AACvE,QAAQ,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC;AACvD,IAAI,GAAG;AACP;AACA,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ;AAC1B,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE;AACpC,QAAQ,aAAa,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,iBAAiB,CAAC;AAChE,QAAQ,eAAe,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC;AACjD,QAAQ,aAAa,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC;AAC/C,QAAQ,iBAAiB,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC;AACnD,QAAQ,iBAAiB,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC;AACnD,QAAQ,eAAe,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC;AACjD,QAAQ,cAAc,CAAC,KAAK,IAAI,CAAC,cAAc,CAAC;AAChD,QAAQ,YAAY,CAAC,OAAO,IAAI,CAAC,YAAY,CAAC;AAC9C,QAAQ,gBAAgB,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC;AAClD,QAAQ,YAAY,CAAC,OAAO,IAAI,CAAC,YAAY,CAAC;AAC9C,QAAQ,YAAY,CAAC,OAAO,IAAI,CAAC,YAAY,CAAC;AAC9C,QAAQ,MAAM,CAAC,aAAa,IAAI,CAAC;AACjC,QAAQ,OAAO,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC;AACzC,QAAQ,eAAe,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC;AACjD,QAAQ,eAAe,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC;AACjD,QAAQ,OAAO,CAAC,YAAY,IAAI,CAAC,eAAe;AAChD,IAAI,GAAG;AACP;AACA,IAAI,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,IAAI;AAC/F;AACA,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM;AAC9B,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE;AAC1C,QAAQ,QAAQ,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC;AACxC,QAAQ,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO;AAChC,IAAI,GAAG;AACP;AACA,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK;AAC5B,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE;AACtC,QAAQ,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB;AACnD,IAAI,GAAG;AACP;AACA,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM;AACxB,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE;AAChC,QAAQ,MAAM,CAAC,aAAa,IAAI,CAAC;AACjC,QAAQ,QAAQ,CAAC,WAAW,IAAI,CAAC,QAAQ,CAAC;AAC1C,QAAQ,OAAO,CAAC,YAAY,IAAI,CAAC,MAAM,CAAC;AACxC,QAAQ,cAAc,CAAC,KAAK,IAAI,CAAC,cAAc;AAC/C,IAAI,GAAG;AACP;AACA,IAAI,EAAE,CAAC,OAAO,CAAC,SAAS;AACxB,IAAI,IAAI,CAAC,iBAAiB,IAAI,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAC9D,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE;AACtD;AACA,IAAI,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO;AACxG,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC;AACnC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;AACnF,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;AAC9B,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE;AAC9D,YAAY,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9C,YAAY,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE;AACtE,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;AAC/B,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE;AAC/D,YAAY,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9C,YAAY,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE;AACvE,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,UAAU;AAC3C,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE;AAC7B,QAAQ,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE;AAC1C,YAAY,EAAE,CAAC,gBAAgB,IAAI,CAAC,WAAW,CAAC;AAChD,YAAY,QAAQ,CAAC,UAAU,IAAI,CAAC,iBAAiB,CAAC;AACtD,YAAY,SAAS,CAAC,SAAS,IAAI,CAAC,kBAAkB,CAAC;AACvD,YAAY,iBAAiB,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC;AAC/D,YAAY,GAAG,CAAC,eAAe,IAAI,CAAC,YAAY,CAAC;AACjD,YAAY,IAAI,CAAC,cAAc,IAAI,CAAC,aAAa,CAAC;AAClD,YAAY,KAAK,CAAC,aAAa,IAAI,CAAC,cAAc,CAAC;AACnD,YAAY,MAAM,CAAC,YAAY,IAAI,CAAC,eAAe,CAAC;AACpD,YAAY,UAAU,CAAC,QAAQ,IAAI,CAAC,mBAAmB,CAAC;AACxD,YAAY,QAAQ,CAAC,UAAU,IAAI,CAAC,iBAAiB,CAAC;AACtD,YAAY,SAAS,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC;AAC9C,YAAY,MAAM,CAAC,YAAY,IAAI,CAAC;AACpC,YAAY,eAAe,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC;AACpD,YAAY,iBAAiB,CAAC,CAAC,IAAI,CAAC,iBAAiB;AACrD,QAAQ,GAAG;AACX,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,QAAQ,CAAC,IAAI;AACpB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AAC5B,QAAQ,IAAI,CAAC,oBAAoB,GAAG;AACpC,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW;AAC/B,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;AAC3B,QAAQ,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AACtC,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ;AAC1B,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACxD,QAAQ,IAAI,CAAC,UAAU,CAAC;AACxB,YAAY,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACxC,YAAY,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;AACrD,QAAQ,EAAE;AACV,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG;AACvB,IAAI,EAAE,qBAAqB,CAAC,CAAC,QAAQ,GAAG;AACxC,QAAQ,qBAAqB,CAAC,CAAC,KAAK,CAAC,EAAE;AACvC,IAAI,CAAC,CAAC,EAAE;AACR,EAAE;AACF;AACA,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG;AAC7H;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AACxB,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACzB,QAAQ,MAAM,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG;AAC3C,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC/B,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE;AACtG,QAAQ,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE;AAChC,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,cAAc,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC7C,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE;AAC7G,QAAQ,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,EAAE;AACvC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;AAC7D,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU;AACnF,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS;AACvF,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,aAAa,EAAE;AAC3F,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC;AACnE,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ;AACnF,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,aAAa,EAAE;AAC/E,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS;AACzF,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,QAAQ,CAAC;AAC1G,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI;AAC7C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM;AACpD,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC/C,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB;AACA,QAAQ,IAAI,CAAC,KAAK,GAAG;AACrB;AACA,QAAQ,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC;AAC3B,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;AAC1D,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;AACtC,gBAAgB,IAAI,CAAC,cAAc,CAAC,OAAO,GAAG;AAC9C,gBAAgB,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3C,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;AAC3E,cAAc,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC;AAC7C,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC;AAC3C,YAAY,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG;AACvG,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1C,gBAAgB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,cAAc,GAAG;AACjE;AACA,gBAAgB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,EAAE;AAC/C,oBAAoB,IAAI,CAAC,iBAAiB,GAAG;AAC7C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE;AAC/D,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;AACtC,YAAY,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;AACxC,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;AAClC,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7B;AACA,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC;AAC1C,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1B,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACzB,QAAQ,GAAG,CAAC,SAAS,CAAC;AACtB;AACA,QAAQ,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC1C,YAAY,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;AACpD,gBAAgB,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAChC,oBAAoB,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACtE,wBAAwB,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE;AACtD,wBAAwB,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG;AAChD,oBAAoB,CAAC;AACrB;AACA,oBAAoB,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7C;AACA,oBAAoB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE;AAChD,oBAAoB,EAAE,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AAC5C,wBAAwB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;AACnD,oBAAoB,CAAC;AACrB;AACA,oBAAoB,EAAE,CAAC,MAAM,CAAC,QAAQ;AACtC,oBAAoB,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE;AACpE,wBAAwB,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC3E,4BAA4B,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACxG,wBAAwB,CAAC;AACzB,oBAAoB,CAAC;AACrB;AACA,oBAAoB,KAAK,CAAC,aAAa,GAAG;AAC1C,oBAAoB,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAC3C;AACA,oBAAoB,GAAG;AACvB,qBAAqB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC;AAC5F,qBAAqB,CAAC;AACtB,qBAAqB,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;AAClC,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrD,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrC,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACvH,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;AACrG,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1F,qBAAqB,EAAE;AACvB,oBAAoB,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC;AAChE,oBAAoB,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACnE,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,oBAAoB,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAC3C;AACA,oBAAoB,GAAG;AACvB,qBAAqB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;AACxE,qBAAqB,CAAC;AACtB,qBAAqB,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM;AACzC,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrD,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrC,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACvH,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;AAClF,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/E,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1F,qBAAqB,EAAE;AACvB,oBAAoB,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE;AACjE,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACvC,YAAY,EAAE,CAAC,IAAI,aAAa,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;AACnE,gBAAgB,OAAO,CAAC,CAAC,CAAC,CAAC;AAC3B,oBAAoB,UAAU,CAAC,CAAC,OAAO;AACvC,gBAAgB,EAAE;AAClB,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AAC9C,gBAAgB,EAAE,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,OAAO,GAAG;AAClH,gBAAgB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;AACrC,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AAC9D,gBAAgB,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC;AACrD,YAAY,CAAC;AACb;AACA,YAAY,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;AAClD,YAAY,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/C,gBAAgB,SAAS,GAAG;AAC5B;AACA,gBAAgB,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,QAAQ;AAC3F,gBAAgB,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC;AACrF,gBAAgB,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;AAClD,oBAAoB,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAClF,wBAAwB,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,GAAG;AACzE,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB;AACA,gBAAgB,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;AACtC,oBAAoB,eAAe,CAAC,KAAK,EAAE;AAC3C,gBAAgB,CAAC;AACjB;AACA,gBAAgB,eAAe,GAAG;AAClC,YAAY,EAAE;AACd;AACA,YAAY,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AAC9C,YAAY,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAC7C,gBAAgB,QAAQ,GAAG;AAC3B;AACA,gBAAgB,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;AACjC,oBAAoB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;AACtC,gBAAgB,CAAC;AACjB;AACA,gBAAgB,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;AACpC,oBAAoB,aAAa,CAAC,KAAK,EAAE;AACzC,gBAAgB,CAAC;AACjB;AACA,gBAAgB,eAAe,GAAG;AAClC,YAAY,EAAE;AACd;AACA,YAAY,KAAK,CAAC,aAAa,CAAC,OAAO,EAAE;AACzC,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,WAAW;AACtB,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACtD,YAAY,KAAK,CAAC,WAAW,CAAC,CAAC,GAAG;AAClC,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK;AAC9C,KAAK,EAAE;AACP,IAAI,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzB,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,WAAW;AAC3E,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAC9B;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC/B,YAAY,IAAI,CAAC,SAAS,CAAC,KAAK,GAAG;AACnC,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACrC,YAAY,IAAI,CAAC,aAAa,GAAG;AACjC,YAAY,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG;AAClD,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5C,QAAQ,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG;AAC/B,QAAQ,IAAI,CAAC,WAAW,CAAC,KAAK,GAAG;AACjC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,GAAG;AACrF,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK;AACvB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AACnC;AACA,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,aAAa,CAAC;AACvF,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,OAAO,CAAC;AACf,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,EAAE;AACnC,KAAK,CAAC,GAAG,KAAK;AACd,KAAK,CAAC,CAAC,GAAG;AACV,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;AAC3C,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,GAAG;AACxB,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,SAAS;AACjC,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,EAAE;AACP,IAAI,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1B,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,WAAW;AAC3E,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,KAAK,GAAG;AACrB;AACA,QAAQ,IAAI,CAAC,aAAa,GAAG;AAC7B,QAAQ,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG;AAC9C;AACA,QAAQ,EAAE,IAAI,CAAC,CAAC,SAAS,CAAC,IAAI,GAAG;AACjC,QAAQ,EAAE,IAAI,CAAC,sBAAsB,EAAE;AACvC,QAAQ,EAAE,IAAI,CAAC,sBAAsB,EAAE;AACvC;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;AAClC,YAAY,IAAI,CAAC,cAAc,CAAC,OAAO,GAAG;AAC1C,YAAY,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;AACvC,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC/C,YAAY,EAAE,oBAAoB,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE;AAC5D,YAAY,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC;AACzC,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5B,YAAY,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG;AAClC,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,iBAAiB,GAAG;AACjC;AACA,QAAQ,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ;AACxE,QAAQ,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI;AACtE,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE;AAClF,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE;AAC1B,YAAY,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;AAC7C,gBAAgB,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;AAClE,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ;AACrC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE;AAC/B,YAAY,IAAI,CAAC,YAAY,CAAC,OAAO,GAAG;AACxC,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE;AAC/B,YAAY,IAAI,CAAC,YAAY,CAAC,OAAO,GAAG;AACxC,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC,QAAQ,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AACjC;AACA,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO;AAClD,QAAQ,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3B,QAAQ,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9B;AACA,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM;AAC9G,QAAQ,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AACxB,KAAK,EAAE;AACP,IAAI,iBAAiB,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACpC,QAAQ,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,GAAG;AAC9C,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO;AAClE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO;AACtD,KAAK,EAAE;AACP,IAAI,kBAAkB,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE;AAC5C,QAAQ,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,EAAE;AACjD,QAAQ,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,EAAE;AACjD,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,kBAAkB,GAAG;AAC3H,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO;AAC/B,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AACtC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AACjE,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AACxB,KAAK,EAAE;AACP,IAAI,kBAAkB,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACrC,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;AAC3C,YAAY,CAAC,CAAC;AACd,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;AACpD,YAAY,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,GAAG;AACjE,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,OAAO,CAAC;AACvB,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE;AACzE,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO;AACzD,KAAK,EAAE;AACP,IAAI,kBAAkB,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC7C,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE;AACtB,YAAY,qBAAqB,CAAC,CAAC,IAAI,CAAC,EAAE;AAC1C,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,qBAAqB,CAAC,CAAC,IAAI,CAAC,EAAE;AAC1C,QAAQ,CAAC;AACT,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,kBAAkB,GAAG;AACzH,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO;AAClC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AACtC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AACpE,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;AACtD,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;AACvE,KAAK,EAAE;AACP,IAAI,YAAY,CAAC,CAAC,QAAQ,CAAC,SAAS,EAAE;AACtC;AACA,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;AAC7D,YAAY,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1D,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AACnC,QAAQ,IAAI,CAAC,WAAW,GAAG;AAC3B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AACxB,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC7B,QAAQ,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;AAC1C,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AAC7B,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ;AAChC,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AAC1E,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI;AACtD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI;AAClD,KAAK,EAAE;AACP,IAAI,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvC;AACA,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;AACjC,YAAY,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;AACnC,YAAY,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC;AACtD,YAAY,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,YAAY,KAAK,CAAC;AAClB,YAAY,CAAC,CAAC;AACd;AACA,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AAC5E,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9C,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;AACjC,YAAY,QAAQ,CAAC,CAAC,QAAQ,CAAC;AAC/B,YAAY,oBAAoB,CAAC,CAAC,KAAK;AACvC,QAAQ,EAAE;AACV,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,WAAW,GAAG;AAC3H,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI;AAC/B,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AAC3G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACnH,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,iBAAiB,CAAC,EAAE;AAC9D,QAAQ,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;AACvD,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACzB;AACA,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AAChE,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,aAAa,GAAG;AAChD;AACA,YAAY,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;AAC3D,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC5C,YAAY,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;AAC7D,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC7C;AACA,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC;AAC/C,YAAY,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;AAC7C,YAAY,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACnC,YAAY,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAClC;AACA,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC;AACjD,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;AAC/C,YAAY,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACpC,YAAY,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACnC;AACA,YAAY,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AAC7C,YAAY,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;AAC3C,YAAY,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AACrC,YAAY,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AACpC;AACA,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC;AAC/C,YAAY,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;AAC7C,YAAY,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AACtC,YAAY,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AACrC;AACA,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK;AAChF,YAAY,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK;AAC3E,YAAY,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO;AAClF,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK;AAClF,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;AAC7E,YAAY,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG;AACnC,YAAY,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;AAC1E,YAAY,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;AACzE,YAAY,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;AAC1E,YAAY,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;AAC5E,YAAY,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;AAC3C,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC3C,gBAAgB,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC/D,gBAAgB,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACzD,YAAY,CAAC;AACb;AACA,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AAC9E,YAAY,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI;AAC1C,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACzD,gBAAgB,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACtE,gBAAgB,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ;AAC3D,gBAAgB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC;AAC1E,gBAAgB,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC;AAC5E,gBAAgB,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AACzD;AACA,gBAAgB,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK;AAChF,gBAAgB,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI;AAC7B,gBAAgB,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE;AAC/D,YAAY,CAAC;AACb;AACA,YAAY,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE;AACnD,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AAC7C;AACA,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACnE,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAClE;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACzD,gBAAgB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC7C,oBAAoB,EAAE,cAAc,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;AACnG,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACzB,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9C;AACA,YAAY,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG;AACjD,YAAY,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,gBAAgB,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACvD;AACA,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB;AACA,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC;AAC3D,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC;AAC7D;AACA,YAAY,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;AAC/C,YAAY,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AAC7C;AACA,YAAY,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;AACjD,YAAY,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;AAC/C;AACA,YAAY,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AAC7C,YAAY,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;AAC3C;AACA,YAAY,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;AAC/C,YAAY,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AAC7C;AACA,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AAC7C,YAAY,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;AAC7C,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC3C,gBAAgB,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,EAAE;AAC9D,YAAY,CAAC;AACb;AACA,YAAY,EAAE,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE;AACtD,YAAY,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,iBAAiB,CAAC,YAAY,CAAC;AAC7D,gBAAgB,IAAI,CAAC,OAAO,CAAC;AAC7B,gBAAgB,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,eAAe;AACjD,YAAY,EAAE;AACd;AACA,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AAC9E,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK;AAC5C,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACzD,gBAAgB,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AACzD;AACA,gBAAgB,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK;AAChF,gBAAgB,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI;AAC7B,gBAAgB,EAAE,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE;AAClE;AACA,gBAAgB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC;AACrD,oBAAoB,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;AACzC,oBAAoB,IAAI,CAAC,OAAO,CAAC,WAAW;AAC5C,gBAAgB,EAAE;AAClB,gBAAgB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;AAC/C,gBAAgB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;AAChD,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,gBAAgB,CAAC;AAC1E,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,iBAAiB,CAAC;AAC5E;AACA,YAAY,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;AAC1E,YAAY,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;AAC9D,YAAY,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,YAAY,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC5C,gBAAgB,EAAE,aAAa,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE;AACpD,gBAAgB,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,aAAa,GAAG;AACnD,gBAAgB,oBAAoB,GAAG;AACvC,gBAAgB,EAAE,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;AAChD,oBAAoB,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;AAC3D,oBAAoB,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC;AAC3D,oBAAoB,EAAE,qBAAqB,CAAC,CAAC,aAAa,CAAC,EAAE;AAC7D,gBAAgB,CAAC;AACjB,YAAY,EAAE;AACd,YAAY,EAAE,qBAAqB,CAAC,CAAC,aAAa,CAAC,EAAE;AACrD;AACA,YAAY,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAC/C;AACA,YAAY,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG;AAC/C,YAAY,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACvD;AACA,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAChD,YAAY,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AACnD,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,WAAW,GAAG;AACpH,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI;AAC3B,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AAC5G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;AAC/D;AACA,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;AAC7E,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU;AAClC,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;AAC9E,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM;AACxD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM;AACpD,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC3C,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;AACtC,YAAY,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,UAAU,CAAC,EAAE;AAClD,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAChD,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;AAClC,YAAY,UAAU,CAAC,CAAC,UAAU,CAAC;AACnC,YAAY,oBAAoB,CAAC,CAAC,KAAK;AACvC,QAAQ,EAAE;AACV,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,aAAa,GAAG;AAC/H,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACjF,SAAS,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK;AACjF,SAAS,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AAC9D,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM;AACjC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;AACjH,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACrH,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,kBAAkB,CAAC,EAAE;AACjE,QAAQ,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;AACxD,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC3B;AACA,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE;AACrC,YAAY,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AAChF,YAAY,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;AACpC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;AACvC,gBAAgB,MAAM,CAAC,IAAI,CAAC;AAC5B,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;AAC/D,YAAY,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;AACjE,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AAC9C,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AAC/C;AACA,YAAY,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACjD,gBAAgB,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,GAAG;AACpD,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACtC,oBAAoB,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,kBAAkB,CAAC,EAAE;AACzF,oBAAoB,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,wBAAwB,CAAC,CAAC,kBAAkB,CAAC,EAAE;AAC9F;AACA,oBAAoB,KAAK,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC/C,oBAAoB,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/C,wBAAwB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC;AAC7E,wBAAwB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC;AAC/E,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB,gBAAgB,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC1D,oBAAoB,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE;AAC7D,gBAAgB,CAAC;AACjB,gBAAgB,GAAG;AACnB,iBAAiB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,aAAa,GAAG;AAChI,iBAAiB,CAAC;AAClB,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM;AACrC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACjD,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACjC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACnH,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;AAC1H,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AACtF,iBAAiB,EAAE;AACnB,gBAAgB,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE;AAChF,YAAY,EAAE;AACd,YAAY,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,kBAAkB,CAAC,EAAE;AAC9E,YAAY,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,wBAAwB,CAAC,CAAC,kBAAkB,CAAC,EAAE;AACnF;AACA,YAAY,EAAE,iBAAiB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AACjD;AACA,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,cAAc,GAAG;AAC/B,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AACxB,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC5B,QAAQ,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE;AAC3D,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AAC/B,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO;AAChD,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE;AACpC,QAAQ,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE;AAClE,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,UAAU,GAAG;AACnG,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AACtC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AAC3D,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AACvC,KAAK,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC;AAChF,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC;AACzC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;AAC/E,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;AACnF,KAAK,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AACpF,KAAK,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;AAC9C,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAC9B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC;AACrF,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,cAAc;AAC7E,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;AACzE,KAAK,CAAC,MAAM,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE;AAC5E,KAAK,CAAC,MAAM,YAAY,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;AAC3E,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM;AACnE,KAAK,CAAC,MAAM,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,UAAU;AACtE,KAAK,CAAC,MAAM,cAAc,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ;AAC5E,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;AACrE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE;AAC7E,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;AACxC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;AAC1F,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE;AACjF,KAAK,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO;AAC3F,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AAC1B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AAC1F,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AAC1F,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACzF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACzF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW;AACzF,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;AAC/E,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC;AACnG,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC;AACzE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;AACxF,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AACtF,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;AAC9C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AACxG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;AACpH,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM;AACrF,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC;AACtC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;AAClG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;AACjG,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,iBAAiB,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI;AACjG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC;AACnD,KAAK,CAAC,MAAM,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;AAC1D,KAAK,CAAC,MAAM,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACrE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;AAC5C,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;AACvE,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAC/G,KAAK,CAAC,MAAM,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE;AACjH,KAAK,CAAC,CAAC,QAAQ,CAAC;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AACxF,KAAK,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;AACzF,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AACxC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AACpF,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC;AACvF,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC;AAC/B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,EAAE,CAAC;AACtF,KAAK,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;AACxF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAChI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM;AACxD,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACxC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,GAAG;AAChF,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,GAAG;AACtG,QAAQ,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,IAAI;AAC/G,YAAY,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,GAAG;AACtH;AACA,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB;AACA,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;AAC9B,YAAY,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE;AACvE,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,YAAY,GAAG;AAC5B;AACA,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AACzD,YAAY,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC;AACrE,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AAC5C,YAAY,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AAC3C,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AAC5C,YAAY,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AAC3C,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AACvD,YAAY,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AACjE,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AACtD,YAAY,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC;AAC3J,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AACxD,YAAY,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC;AACnE,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AACtD,YAAY,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC;AAC/D,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAChF,YAAY,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;AACnD,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;AAC/F,YAAY,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE;AACtF,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC3B,YAAY,OAAO,CAAC,CAAC,OAAO;AAC5B,QAAQ,EAAE;AACV;AACA,QAAQ,QAAQ,CAAC,kBAAkB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9C,YAAY,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC/D,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;AAC1D,oBAAoB,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAClD,oBAAoB,KAAK,CAAC;AAC1B,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,gBAAgB,YAAY,CAAC,WAAW,EAAE;AAC1C,YAAY,CAAC;AACb;AACA,aAAa,GAAG;AAChB,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/D,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM;AACrC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AAC7C,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC/G,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AACzC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AACxC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC;AACzF,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,aAAa,EAAE;AACf,YAAY,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE;AACzD;AACA,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;AAChC,gBAAgB,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE;AACrC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;AACxC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;AACvC,gBAAgB,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE;AACrC,oBAAoB,WAAW,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,qBAAqB,CAAC;AACvE,oBAAoB,IAAI,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;AAC/C,oBAAoB,OAAO,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC;AACrD,oBAAoB,MAAM,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;AACnD,oBAAoB,QAAQ,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC;AACvD,oBAAoB,UAAU,CAAC,CAAC,KAAK,CAAC,oBAAoB;AAC1D,gBAAgB,GAAG;AACnB,gBAAgB,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,IAAI,EAAE;AACvD,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;AAC5C,YAAY,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC;AACnC,gBAAgB,kBAAkB,EAAE;AACpC,oBAAoB,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG;AAClH,oBAAoB,MAAM,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;AAC/C,oBAAoB,OAAO,CAAC,CAAC,OAAO;AACpC,gBAAgB,GAAG;AACnB,YAAY,GAAG;AACf,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE;AAC1C;AACA,QAAQ,QAAQ,CAAC,iBAAiB,EAAE,CAAC,CAAC;AACtC,YAAY,GAAG,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC;AACpD,YAAY,KAAK,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AAC7C,gBAAgB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,EAAE;AAChD,gBAAgB,EAAE,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;AAC5C,oBAAoB,KAAK,CAAC;AAC1B,gBAAgB,CAAC;AACjB;AACA,gBAAgB,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9C;AACA,gBAAgB,EAAE,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;AAChD,oBAAoB,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,EAAE;AAC7F,oBAAoB,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,wBAAwB,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC3D,oBAAoB,CAAC;AACrB,oBAAoB,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,EAAE;AAC1E,gBAAgB,CAAC;AACjB;AACA,gBAAgB,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE;AAC/C,oBAAoB,MAAM,CAAC,CAAC,KAAK,CAAC;AAClC,oBAAoB,MAAM,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC;AACjD,oBAAoB,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AAC7C,oBAAoB,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;AACzC,oBAAoB,SAAS,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AAC/C,oBAAoB,WAAW,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACnD,oBAAoB,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3C,oBAAoB,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3C,oBAAoB,KAAK,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC;AACnD,oBAAoB,MAAM,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC;AACrD,oBAAoB,SAAS,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC;AAC3D,oBAAoB,kBAAkB,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,kBAAkB,CAAC;AAC7E,oBAAoB,IAAI,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;AACjD,oBAAoB,oBAAoB,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,oBAAoB,CAAC;AACjF,oBAAoB,OAAO,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC;AACvD,oBAAoB,OAAO,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC;AACvD,oBAAoB,OAAO,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC;AACvD,oBAAoB,kBAAkB,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,kBAAkB,CAAC;AAC7E,oBAAoB,eAAe,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC;AAC3D,oBAAoB,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC;AACvD,oBAAoB,iBAAiB,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC;AAC/D,oBAAoB,cAAc,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;AACzD,oBAAoB,YAAY,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC;AACrD,oBAAoB,eAAe,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC;AAC3D,oBAAoB,SAAS,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AAC/C,oBAAoB,WAAW,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACnD,oBAAoB,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC;AACvD,oBAAoB,sBAAsB,CAAC,CAAC,KAAK,CAAC,sBAAsB,CAAC;AACzE,oBAAoB,SAAS,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AAC/C,oBAAoB,iBAAiB,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,iBAAiB,CAAC;AAC3E,oBAAoB,mBAAmB,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,mBAAmB,CAAC;AAC/E,oBAAoB,iBAAiB,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,iBAAiB,CAAC;AAC3E,oBAAoB,WAAW,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC;AAC/D,oBAAoB,SAAS,CAAC,CAAC,KAAK,CAAC,SAAS;AAC9C,gBAAgB,GAAG;AACnB;AACA,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;AAC3C,oBAAoB,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,KAAK,EAAE;AAC5D,gBAAgB,CAAC;AACjB,gBAAgB,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;AAClD,oBAAoB,KAAK,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK;AAClD,gBAAgB,GAAG;AACnB;AACA,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,oBAAoB,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;AACvE,oBAAoB,YAAY,CAAC,SAAS,EAAE;AAC5C,gBAAgB,CAAC;AACjB;AACA,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAClF,oBAAoB,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE;AAChD,gBAAgB,CAAC;AACjB;AACA,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;AACtC,oBAAoB,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;AACpE,wBAAwB,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO;AAClG,wBAAwB,kBAAkB,CAAC,CAAC,UAAU,CAAC;AACvD,wBAAwB,UAAU,CAAC,CAAC,SAAS,CAAC,UAAU;AACxD,oBAAoB,GAAG;AACvB;AACA,oBAAoB,KAAK,CAAC,SAAS,CAAC,aAAa,CAAC,YAAY,EAAE;AAChE,gBAAgB,CAAC;AACjB;AACA,gBAAgB,EAAE,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;AAChD,oBAAoB,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE;AAC/C,wBAAwB,IAAI,CAAC,CAAC,UAAU;AACxC,oBAAoB,GAAG;AACvB,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,2BAA2B,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAChG;AACA,YAAY,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC;AAChD;AACA,YAAY,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACzE,YAAY,iBAAiB,GAAG;AAChC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,YAAY,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;AACpC,YAAY,kBAAkB,CAAC,KAAK,EAAE;AACtC;AACA,YAAY,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;AACzE,YAAY,iBAAiB,GAAG;AAChC,QAAQ,CAAC,CAAC,EAAE;AACZ,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AACxC,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,aAAa,CAAC;AACzF,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;AACtE,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,aAAa,CAAC;AAC/E,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC1B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM;AACxD,KAAK,EAAE;AACP,IAAI,cAAc,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACvC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,GAAG;AACjF,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,GAAG;AACzF;AACA,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AAC1C,YAAY,UAAU,CAAC,CAAC,CAAC;AACzB,gBAAgB,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE;AAC9B,gBAAgB,GAAG,CAAC,EAAE,OAAO,CAAC,GAAG;AACjC,YAAY,CAAC;AACb,QAAQ,GAAG;AACX,QAAQ,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;AACxB,QAAQ,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE;AACjC,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACnC,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB;AACA,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE;AAChH;AACA,QAAQ,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AAClD,YAAY,OAAO,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AACtC,gBAAgB,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;AAC/C,oBAAoB,OAAO,CAAC,CAAC,OAAO,CAAC;AACrC,oBAAoB,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI;AACtC,gBAAgB,GAAG;AACnB,YAAY,EAAE;AACd,YAAY,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AACpC,gBAAgB,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE;AAC5D,YAAY,CAAC;AACb,QAAQ,GAAG;AACX;AACA,QAAQ,IAAI,CAAC,aAAa,CAAC,YAAY,EAAE;AACzC,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,eAAe,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE;AAClH,QAAQ,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE;AAC3C,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,eAAe,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACzC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE;AACvH,QAAQ,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE;AACjD,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,cAAc,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAChC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE;AACpH,QAAQ,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG;AACzC,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9C,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE;AACnH,QAAQ,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE;AACtD,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACrC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE;AAC/G,QAAQ,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE;AAC7C,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC/C,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;AACjD,KAAK,EAAE;AACP,IAAI,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC7B,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;AAChD,KAAK,EAAE;AACP,IAAI,oBAAoB,CAAC,CAAC,QAAQ,GAAG;AACrC;AACA,QAAQ,0EAA0E;AAClF,QAAQ,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ;AAClC,QAAQ,0EAA0E;AAClF,QAAQ,GAAG,CAAC,cAAc,UAAU,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE;AAClE,YAAY,aAAa,WAAW,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACjE,YAAY,aAAa,WAAW,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACjE,YAAY,iBAAiB,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,EAAE;AACrE,YAAY,SAAS,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AACrD,YAAY,QAAQ,gBAAgB,CAAC,CAAC,IAAI,CAAC;AAC3C;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,EAAE;AACvC;AACA,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;AACzD,gBAAgB,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG;AACrE,gBAAgB,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM;AACnE,gBAAgB,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AACjC,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE;AAChD,gBAAgB,OAAO,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7F,gBAAgB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAC5D,gBAAgB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAC5D,gBAAgB,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,EAAE;AACnE,gBAAgB,OAAO,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AAClF,gBAAgB,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;AACnF,gBAAgB,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;AACnF,gBAAgB,OAAO,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AAClF,gBAAgB,SAAS,CAAC,EAAE,iBAAiB,CAAC;AAC9C,gBAAgB,OAAO,CAAC,IAAI,cAAc,CAAC;AAC3C,gBAAgB,MAAM,CAAC,KAAK,aAAa;AACzC,YAAY,GAAG;AACf;AACA,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE;AAC5C,gBAAgB,OAAO,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACrF,gBAAgB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAC5D,gBAAgB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAC5D,gBAAgB,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE;AAC/D,gBAAgB,OAAO,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AAC9E,gBAAgB,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AAC/E,gBAAgB,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AAC/E,gBAAgB,OAAO,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AAC9E,gBAAgB,SAAS,CAAC,EAAE,aAAa,CAAC;AAC1C,gBAAgB,OAAO,CAAC,IAAI,cAAc,CAAC;AAC3C,gBAAgB,MAAM,CAAC,KAAK,aAAa;AACzC,YAAY,GAAG;AACf;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE;AACxC,gBAAgB,IAAI,CAAC,cAAc,CAAC,OAAO,GAAG;AAC9C,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;AAChE,gBAAgB,IAAI,CAAC,UAAU,CAAC,OAAO,GAAG;AAC1C,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE;AAC3B,gBAAgB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE;AACjD,oBAAoB,OAAO,CAAC,CAAC,CAAC;AAC9B,wBAAwB,IAAI,CAAC,cAAc,CAAC;AAC5C,wBAAwB,IAAI,CAAC,UAAU;AACvC,oBAAoB,EAAE;AACtB,oBAAoB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAChE,oBAAoB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB;AAC/D,gBAAgB,GAAG;AACnB;AACA,gBAAgB,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;AACzD;AACA,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AACnC,oBAAoB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;AAC5C,wBAAwB,IAAI,CAAC,aAAa,CAAC;AAC3C,wBAAwB,CAAC,MAAM,CAAC,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC;AAC9D,oBAAoB,EAAE;AACtB,gBAAgB,CAAC,IAAI,CAAC;AACtB,oBAAoB,IAAI,CAAC,UAAU,CAAC;AACpC,wBAAwB,IAAI,CAAC,aAAa,CAAC;AAC3C,wBAAwB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC;AACxF,oBAAoB,EAAE;AACtB,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;AAChD,KAAK,EAAE;AACP,IAAI,oBAAoB,CAAC,CAAC,QAAQ,GAAG;AACrC,QAAQ,0EAA0E;AAClF,QAAQ,EAAE,CAAC,UAAU,CAAC,QAAQ;AAC9B,QAAQ,0EAA0E;AAClF,QAAQ,GAAG,CAAC,qBAAqB,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,EAAE;AACzE,YAAY,iBAAiB,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,EAAE;AACrE,YAAY,qBAAqB,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,EAAE;AACzE,YAAY,sBAAsB,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,EAAE;AAC1E,YAAY,sBAAsB,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,EAAE;AAC1E,YAAY,aAAa,WAAW,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACjE,YAAY,mBAAmB,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,EAAE;AACvE,YAAY,mBAAmB,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,EAAE;AACvE,YAAY,oBAAoB,IAAI,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,EAAE;AACxE,YAAY,cAAc,UAAU,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE;AAClE,YAAY,aAAa,WAAW,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACjE,YAAY,SAAS,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AACrD,YAAY,OAAO,iBAAiB,CAAC,CAAC,GAAG;AACzC,YAAY,QAAQ,gBAAgB,CAAC,CAAC,IAAI,CAAC;AAC3C;AACA;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;AAC3C;AACA,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE;AAC1D,gBAAgB,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE;AACzD,gBAAgB,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;AACnE,gBAAgB,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG;AACrE,gBAAgB,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM;AACnE,gBAAgB,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AACjC,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AACzC,gBAAgB,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE;AAChE,oBAAoB,OAAO,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7F,oBAAoB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAChE,oBAAoB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAChE,oBAAoB,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE;AACjE,oBAAoB,OAAO,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;AACpF,oBAAoB,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;AACrF,oBAAoB,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;AACrF,oBAAoB,OAAO,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;AACpF,oBAAoB,OAAO,CAAC,IAAI,qBAAqB,CAAC;AACtD,oBAAoB,SAAS,CAAC,EAAE,iBAAiB,CAAC;AAClD,oBAAoB,OAAO,CAAC,IAAI,qBAAqB,CAAC;AACtD,oBAAoB,OAAO,CAAC,IAAI,qBAAqB,CAAC;AACtD,oBAAoB,MAAM,CAAC,KAAK,iBAAiB,CAAC;AAClD,oBAAoB,OAAO,CAAC,IAAI,cAAc,CAAC;AAC/C,oBAAoB,MAAM,CAAC,KAAK,aAAa;AAC7C,gBAAgB,IAAI;AACpB;AACA,gBAAgB,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE;AACjE,oBAAoB,OAAO,CAAC,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/F,oBAAoB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAChE,oBAAoB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAChE,oBAAoB,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE;AAClE,oBAAoB,OAAO,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AACrF,oBAAoB,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AACtF,oBAAoB,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AACtF,oBAAoB,OAAO,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AACrF,oBAAoB,OAAO,CAAC,IAAI,sBAAsB,CAAC;AACvD,oBAAoB,SAAS,CAAC,EAAE,iBAAiB,CAAC;AAClD,oBAAoB,OAAO,CAAC,IAAI,sBAAsB,CAAC;AACvD,oBAAoB,OAAO,CAAC,IAAI,sBAAsB,CAAC;AACvD,oBAAoB,MAAM,CAAC,KAAK,iBAAiB,CAAC;AAClD,oBAAoB,OAAO,CAAC,IAAI,cAAc,CAAC;AAC/C,oBAAoB,MAAM,CAAC,KAAK,aAAa;AAC7C,gBAAgB,IAAI;AACpB,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AACzC,gBAAgB,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE;AAC9D,oBAAoB,OAAO,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACzF,oBAAoB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAChE,oBAAoB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAChE,oBAAoB,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE;AAC/D,oBAAoB,OAAO,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AAClF,oBAAoB,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AACnF,oBAAoB,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AACnF,oBAAoB,OAAO,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AAClF,oBAAoB,SAAS,CAAC,EAAE,aAAa,CAAC;AAC9C,oBAAoB,OAAO,CAAC,IAAI,cAAc,CAAC;AAC/C,oBAAoB,MAAM,CAAC,KAAK,aAAa;AAC7C,gBAAgB,IAAI;AACpB,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;AAC7C,gBAAgB,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE;AAClE,oBAAoB,OAAO,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACjG,oBAAoB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAChE,oBAAoB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAChE,oBAAoB,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE;AACnE,oBAAoB,OAAO,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AACtF,oBAAoB,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;AACvF,oBAAoB,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;AACvF,oBAAoB,OAAO,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AACtF,oBAAoB,SAAS,CAAC,EAAE,mBAAmB,CAAC;AACpD,oBAAoB,OAAO,CAAC,IAAI,cAAc,CAAC;AAC/C,oBAAoB,MAAM,CAAC,KAAK,aAAa;AAC7C,gBAAgB,IAAI;AACpB,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;AAC7C,gBAAgB,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE;AACpE,oBAAoB,OAAO,CAAC,IAAI,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACrG,oBAAoB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAChE,oBAAoB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAChE,oBAAoB,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,EAAE;AACrE,oBAAoB,OAAO,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE;AACxF,oBAAoB,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE;AACzF,oBAAoB,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE;AACzF,oBAAoB,OAAO,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE;AACxF,oBAAoB,SAAS,CAAC,EAAE,mBAAmB,CAAC;AACpD,oBAAoB,OAAO,CAAC,IAAI,cAAc,CAAC;AAC/C,oBAAoB,MAAM,CAAC,KAAK,aAAa;AAC7C,gBAAgB,IAAI;AACpB;AACA,gBAAgB,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE;AACrE,oBAAoB,OAAO,CAAC,IAAI,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACvG,oBAAoB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAChE,oBAAoB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAChE,oBAAoB,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,EAAE;AACtE,oBAAoB,OAAO,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE;AACzF,oBAAoB,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE;AAC1F,oBAAoB,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE;AAC1F,oBAAoB,OAAO,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE;AACzF,oBAAoB,SAAS,CAAC,EAAE,oBAAoB,CAAC;AACrD,oBAAoB,OAAO,CAAC,IAAI,cAAc,CAAC;AAC/C,oBAAoB,MAAM,CAAC,KAAK,aAAa;AAC7C,gBAAgB,IAAI;AACpB;AACA,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC7B,gBAAgB,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE;AAClD,oBAAoB,OAAO,CAAC,YAAY,OAAO,CAAC;AAChD,oBAAoB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAChE,oBAAoB,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB;AAC/D,gBAAgB,GAAG;AACnB;AACA,gBAAgB,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;AACxD,gBAAgB,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AACvE;AACA,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AACnC,oBAAoB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;AAC5C,wBAAwB,IAAI,CAAC,UAAU,CAAC;AACxC,wBAAwB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC;AAC1F,oBAAoB,EAAE;AACtB,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,oBAAoB,IAAI,CAAC,UAAU,CAAC;AACpC,wBAAwB,IAAI,CAAC,UAAU,CAAC;AACxC,wBAAwB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC;AAC1F,oBAAoB,EAAE;AACtB,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ;AACzC,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;AACvB,KAAK,EAAE;AACP,IAAI,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC7B,QAAQ,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC;AACnC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI;AAC7C,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/B,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE;AAC9E,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,GAAG;AAC9I,aAAa,CAAC;AACd,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;AAC1B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AAC7C,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC/G,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;AACxD,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,aAAa,EAAE;AACf,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACtD;AACA,YAAY,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;AACvC;AACA,YAAY,IAAI,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,EAAE;AAChD;AACA,YAAY,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAClD;AACA,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE;AACtC,gBAAgB,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE;AACrD,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,GAAG,GAAG;AACN,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,GAAG;AAC9E,KAAK,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ;AAC5E,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ;AAClF,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;AAClD,KAAK,CAAC,CAAC,CAAC,MAAM;AACd,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG;AACtF,KAAK,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;AAC3G,KAAK,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/E,KAAK,CAAC,MAAM,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC;AAClC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AAC9E,KAAK,CAAC,MAAM,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;AACpF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG;AACvE,KAAK,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ;AAC/E,KAAK,CAAC,MAAM,EAAE,CAAC;AACf,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO;AACrF,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC;AACtG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO;AACpD,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAClE,QAAQ,GAAG,CAAC,OAAO,CAAC;AACpB,QAAQ,EAAE,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AACzC,YAAY,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;AAC9B,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,OAAO,CAAC,CAAC,CAAC,CAAC;AACvB,gBAAgB,OAAO,CAAC,CAAC,OAAO,CAAC;AACjC,gBAAgB,QAAQ,CAAC,CAAC,QAAQ,CAAC;AACnC,gBAAgB,SAAS,CAAC,CAAC,SAAS,CAAC;AACrC,gBAAgB,MAAM,CAAC,CAAC,MAAM;AAC9B,YAAY,EAAE;AACd,QAAQ,CAAC;AACT;AACA,QAAQ,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AAClD;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtE,YAAY,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO;AACxD,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE;AACvD,QAAQ,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,EAAE;AAC3C,QAAQ,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AAClE;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,UAAU,GAAG;AACvG,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO;AAC7B,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC7D,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,QAAQ;AACtE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,SAAS;AACxD,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;AACzC,YAAY,OAAO,CAAC,CAAC,OAAO,CAAC;AAC7B,YAAY,QAAQ,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;AACvC,YAAY,SAAS,CAAC,CAAC,OAAO,CAAC,SAAS;AACxC,QAAQ,GAAG;AACX,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;AACzE,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC;AAC/E,KAAK,CAAC,CAAC,CAAC,MAAM;AACd,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG;AAC/E,KAAK,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AAC9E,KAAK,CAAC,MAAM,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;AACpF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG;AACvE,KAAK,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ;AAC/E,KAAK,CAAC,MAAM,EAAE,CAAC;AACf,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO;AACvD,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC7D,QAAQ,GAAG,CAAC,CAAC,CAAC;AACd;AACA,QAAQ,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AAC1C,QAAQ,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE;AAC7D;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvB,YAAY,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,EAAE;AACpE,YAAY,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO;AACrE,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,aAAa,GAAG;AAChE,aAAa,CAAC;AACd,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO;AACpC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AAC7C,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG;AAChF,aAAa,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7C,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AAC1C,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,QAAQ;AAC1E,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,SAAS;AAC5D,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,aAAa,EAAE;AACf,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;AAChD,gBAAgB,OAAO,CAAC,CAAC,OAAO,CAAC;AACjC,gBAAgB,QAAQ,CAAC,CAAC,QAAQ,CAAC;AACnC,gBAAgB,SAAS,CAAC,CAAC,SAAS;AACpC,YAAY,GAAG;AACf,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE;AAC3E,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC;AAC/B,KAAK,CAAC,CAAC,CAAC,MAAM;AACd,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;AACzE,KAAK,CAAC,MAAM,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC;AACxE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO;AACvD,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACxC,QAAQ,GAAG,CAAC,CAAC,CAAC;AACd;AACA,QAAQ,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AAC1C,QAAQ,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE;AAC7D;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvB,YAAY,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,GAAG;AAChD,YAAY,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAChD,YAAY,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM;AAChE,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,aAAa,GAAG;AAChE,aAAa,CAAC;AACd,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO;AACpC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AAC7C,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG;AAChF,aAAa,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7C,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AACjE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,aAAa,EAAE;AACf,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;AAChD,gBAAgB,OAAO,CAAC,CAAC,OAAO;AAChC,YAAY,GAAG;AACf,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS;AAC/E,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC;AACjB,KAAK,CAAC,CAAC,CAAC,MAAM;AACd,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO;AACtD,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC/B,QAAQ,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,YAAY,IAAI,CAAC,eAAe,CAAC,GAAG,GAAG,OAAO,GAAG;AACjD,QAAQ,CAAC;AACT,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,aAAa,GAAG;AACjH,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO;AAC/B,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE;AAC/C,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,KAAK,GAAG;AACR,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE;AACzE,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7D,KAAK,CAAC,CAAC,CAAC,MAAM;AACd,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;AACzE,KAAK,CAAC,MAAM,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5D,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;AAClF,KAAK,EAAE;AACP,IAAI,cAAc,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACzC,QAAQ,GAAG,CAAC,CAAC,CAAC;AACd;AACA,QAAQ,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AAC1C,QAAQ,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE;AAC7D;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,EAAE;AAC3C,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC;AACpC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,sBAAsB;AACtE,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK;AACrC,KAAK,EAAE;AACP,IAAI,sBAAsB,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC9C;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACpC,gBAAgB,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/E,oBAAoB,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM;AACzC,oBAAoB,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAClD,wBAAwB,IAAI,CAAC,UAAU,CAAC,OAAO,GAAG;AAClD,oBAAoB,CAAC;AACrB,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,oBAAoB,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG;AAC7C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AACxC,gBAAgB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjC,oBAAoB,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM;AAC5C,oBAAoB,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG;AACjD,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,oBAAoB,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAClD,wBAAwB,IAAI,CAAC,cAAc,CAAC,OAAO,GAAG;AACtD,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,MAAM,EAAE;AACR;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ;AACxC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,YAAY;AAC5D,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO;AACnC,KAAK,EAAE;AACP,IAAI,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACxC,QAAQ,IAAI,CAAC,YAAY,GAAG;AAC5B;AACA,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAChD,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AAC9D;AACA,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,GAAG,CAAC,EAAE;AACpD;AACA,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,GAAG;AAC7D;AACA,QAAQ,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;AACtD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO;AACpD,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,YAAY;AAC5D,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,EAAE;AACP,IAAI,YAAY,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC/B,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;AAClC,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAClB,YAAY,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,GAAG,EAAE;AAC5C,YAAY,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;AACnC,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;AAC7E,KAAK,CAAC,CAAC,CAAC,MAAM;AACd,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,GAAG;AACtH,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,eAAe,CAAC;AAC9C,KAAK,EAAE;AACP,IAAI,2BAA2B,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpD,QAAQ,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACzB,YAAY,IAAI,CAAC,CAAC,KAAK,EAAE;AACzB,gBAAgB,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC;AACjD,YAAY,IAAI,CAAC,CAAC,KAAK,EAAE;AACzB,gBAAgB,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC;AACjD,YAAY,IAAI,CAAC,CAAC,GAAG,EAAE;AACvB,gBAAgB,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC;AAC/C,YAAY,OAAO,CAAC;AACpB,gBAAgB,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC;AACnD,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC/B,QAAQ,GAAG,CAAC,CAAC,CAAC;AACd,YAAY,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC;AACjD,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACxC,YAAY,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AACxF,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,oBAAoB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACtC,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG;AAC7B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;AAC9D,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,EAAE;AACP,IAAI,oBAAoB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACtC,QAAQ,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,KAAK,CAAC;AACxC;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;AAClC,YAAY,IAAI,CAAC,cAAc,CAAC,OAAO,GAAG;AAC1C,YAAY,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;AACvC,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC;AACvF,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;AAC/D,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,EAAE;AACP,IAAI,iBAAiB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACnC,QAAQ,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC;AACvC;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AAChC,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;AACtC,gBAAgB,MAAM,CAAC;AACvB,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzE,gBAAgB,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,cAAc,EAAE;AAC5D,oBAAoB,EAAE,CAAC,UAAU,IAAI,CAAC,qBAAqB,CAAC;AAC5D,oBAAoB,QAAQ,CAAC,IAAI,IAAI,CAAC,sBAAsB,CAAC;AAC7D,oBAAoB,SAAS,CAAC,GAAG,IAAI,CAAC,uBAAuB,CAAC;AAC9D,oBAAoB,MAAM,CAAC,MAAM,IAAI,CAAC,oBAAoB,CAAC;AAC3D,oBAAoB,MAAM,CAAC,MAAM,IAAI,CAAC,oBAAoB,CAAC;AAC3D,oBAAoB,KAAK,CAAC,OAAO,IAAI,CAAC,mBAAmB,CAAC;AAC1D,oBAAoB,WAAW,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;AAClD,oBAAoB,SAAS,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;AAChD,oBAAoB,MAAM,CAAC,MAAM,IAAI;AACrC,gBAAgB,GAAG;AACnB;AACA,gBAAgB,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE;AACpE,YAAY,CAAC;AACb,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI;AACnG,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,GAAG;AACH;AACA;AACA,GAAG;AACH,CAAC,CAAC,CAAC,gBAAgB,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACjF,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC;AAC3D,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACnB,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,EAAE;AACH,QAAQ,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AACtC,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,EAAE;AACxC;AACA,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AACvB,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE;AAChE,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC;AACjE,IAAI,EAAE;AACN,CAAC;AACD;AACA;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,EAAE;AACH,QAAQ,CAAC,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,eAAe,CAAC;AACtF,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC;AACpB,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AACvB;AACA,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI;AAC/D,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7C,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG;AACpD,QAAQ,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,YAAY,UAAU,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,UAAU,CAAC,EAAE;AAClD,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG;AACnE,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,YAAY,GAAG,CAAC,CAAC;AACjB,cAAc,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,UAAU,EAAE;AACxD,cAAc,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC;AACvC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzB,cAAc,EAAE,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC;AACxC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC;AAC7D,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/B,YAAY,eAAe,CAAC,UAAU,EAAE;AACxC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,UAAU,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACxD,gBAAgB,eAAe,CAAC,UAAU,EAAE;AAC5C,YAAY,GAAG;AACf,YAAY,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACnE,gBAAgB,YAAY,EAAE;AAC9B,oBAAoB,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC3C,oBAAoB,MAAM,CAAC,CAAC,kBAAkB;AAC9C,gBAAgB,GAAG;AACnB,YAAY,GAAG;AACf,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC5B,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,YAAY,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK;AAC3E,YAAY,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE;AAC3C,gBAAgB,GAAG,CAAC,CAAC,UAAU,CAAC;AAChC,gBAAgB,iBAAiB,CAAC,CAAC,UAAU,CAAC,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAC/E,oBAAoB,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC;AAC5E,gBAAgB,mBAAmB,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC;AAChE,gBAAgB,WAAW,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC;AAChD,gBAAgB,SAAS,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC;AAC5C,gBAAgB,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5C,oBAAoB,eAAe,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE;AACxD,gBAAgB,CAAC;AACjB,YAAY,GAAG;AACf,YAAY,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACrE,gBAAgB,YAAY,CAAC,CAAC,KAAK,CAAC,EAAE;AACtC,YAAY,CAAC,CAAC,EAAE;AAChB;AACA,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;AACxE,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;AAC7D,gBAAgB,CAAC,UAAU,CAAC,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC;AACzG,gBAAgB,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,UAAU,CAAC,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAC3F,oBAAoB,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC;AAC5E,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC,mBAAmB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AAC/D,gBAAgB,UAAU,CAAC,mBAAmB,CAAC,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC;AAC5E,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AACrD,gBAAgB,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC;AACxD,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,gBAAgB,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM;AACpC,gBAAgB,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,CAAC,UAAU,CAAC,EAAE;AACtE,gBAAgB,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;AACpE,gBAAgB,eAAe,CAAC,CAAC,gBAAgB,CAAC,EAAE;AACpD,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,EAAE,MAAM,CAAC,aAAa;AACtC,gBAAgB,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,EAAE;AAClF,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;AACrC,oBAAoB,YAAY,CAAC,CAAC,CAAC;AACnC,wBAAwB,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE;AAC7D,wBAAwB,MAAM,CAAC,CAAC,UAAU;AAC1C,oBAAoB,GAAG;AACvB,oBAAoB,MAAM,CAAC;AAC3B,gBAAgB,CAAC;AACjB,gBAAgB,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;AAC7F,gBAAgB,cAAc,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE;AACrE,YAAY,CAAC;AACb,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc;AAClE,YAAY,cAAc,CAAC,UAAU,CAAC,CAAC,UAAU,EAAE;AACnD,QAAQ,CAAC;AACT,IAAI,GAAG;AACP,CAAC;AACD;AACA,QAAQ,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC9C,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AACzC,QAAQ,MAAM,CAAC,OAAO,CAAC;AACvB,IAAI,CAAC;AACL;AACA,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACvB,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC5B,QAAQ,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AAClD,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAC7B,YAAY,OAAO,CAAC,EAAE,CAAC,CAAC;AACxB,YAAY,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE;AAC9E;AACA,QAAQ,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;AAC7C,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACzB,YAAY,OAAO,SAAS,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC5D,YAAY,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAChD,QAAQ,CAAC;AACT,QAAQ,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACxB,QAAQ,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAChD,YAAY,OAAO,CAAC,SAAS,CAAC,CAAC;AAC/B,YAAY,CAAC,aAAa,CAAC,OAAO,CAAC;AACnC,QAAQ,EAAE;AACV,IAAI,CAAC;AACL;AACA,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AAC9B,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AAChC,IAAI,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;AACpB,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC1B,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC1B,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AACvC,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC3E,gBAAgB,OAAO,CAAC,EAAE,CAAC;AAC3B,gBAAgB,OAAO,CAAC,EAAE,CAAC;AAC3B,gBAAgB,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;AAC3B,gBAAgB,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG;AAC9B,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACvB,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACvB,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACjE,YAAY,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACpE,QAAQ,CAAC;AACT,QAAQ,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACrC,IAAI,CAAC;AACL;AACA,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;AACtC,IAAI,EAAE,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;AACtD,QAAQ,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,WAAW,IAAI;AACjE,IAAI,CAAC;AACL;AACA,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE;AAC1B,QAAQ,OAAO,CAAC,CAAC,OAAO,CAAC;AACzB,QAAQ,QAAQ,CAAC,CAAC,QAAQ,CAAC;AAC3B,QAAQ,SAAS,CAAC,CAAC,SAAS,CAAC;AAC7B,QAAQ,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AAC/B,QAAQ,WAAW,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;AACzC,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC;AACrB,QAAQ,MAAM,CAAC,CAAC,MAAM,CAAC;AACvB,QAAQ,YAAY,CAAC,CAAC,OAAO,CAAC,YAAY;AAC1C,IAAI,GAAG;AACP,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;AACzE,CAAC,EAAE;AACH,QAAQ,CAAC,eAAe,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC/C,IAAI,GAAG,CAAC,CAAC,CAAC;AACV,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAClD,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClD,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;AACd,CAAC;AACD;AACA,+EAA+E;AAC/E,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS;AACtD,+EAA+E;AAC/E,QAAQ,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,EAAE;AAC9C,IAAI,MAAM,CAAC,EAAE,qBAAqB,CAAC,CAAC,QAAQ,GAAG;AAC/C,QAAQ,UAAU,CAAC,CAAC,MAAM,CAAC,EAAE;AAC7B,IAAI,CAAC,CAAC,EAAE;AACR,CAAC;AACD;AACA;AACA,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS;AAC3C,QAAQ,CAAC,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACzC,IAAI,EAAE,qBAAqB,CAAC,CAAC,QAAQ,GAAG;AACxC,QAAQ,kBAAkB,CAAC,CAAC,MAAM,CAAC,EAAE;AACrC,IAAI,GAAG;AACP,CAAC;AACD;AACA;AACA,EAAE,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ;AAC7C,QAAQ,CAAC,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC1C,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;AACrC,QAAQ,MAAM,CAAC;AACf,IAAI,CAAC;AACL,IAAI,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,IAAI,MAAM,CAAC,qBAAqB,CAAC,CAAC;AAClC,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;AACjB,QAAQ,MAAM,CAAC,iBAAiB,CAAC;AACjC;AACA,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC,QAAQ,GAAG;AAClC,QAAQ,oBAAoB,CAAC,CAAC,MAAM,CAAC,EAAE;AACvC,IAAI,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,EAAE;AAClC,CAAC;AACD;AACA;AACA,EAAE,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS;AACjE,QAAQ,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACvC,IAAI,GAAG,CAAC,WAAW,CAAC;AACpB,QAAQ,SAAS,CAAC;AAClB,QAAQ,OAAO,CAAC;AAChB,QAAQ,CAAC,CAAC;AACV,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;AACtC,QAAQ,WAAW,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AAC9B,QAAQ,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,qBAAqB,CAAC;AAC/D,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC;AAC9D;AACA,QAAQ,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE;AAC3C,QAAQ,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE;AAC3C;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC5D,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;AAChD,gBAAgB,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AAC3D,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,YAAY,EAAE,CAAC,IAAI,CAAC,KAAK;AACzB,YAAY,oBAAoB,CAAC,CAAC,MAAM,CAAC,EAAE;AAC3C,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,CAAC;AACD;AACA;AACA,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI;AACvD,QAAQ,CAAC,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC1C,IAAI,GAAG,CAAC,CAAC,CAAC;AACV,IAAI,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,KAAK,CAAC;AACtC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACzD,QAAQ,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC/C,IAAI,CAAC;AACL,CAAC;AACD;AACA;AACA;AACA,+EAA+E;AAC/E,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;AAC/B,+EAA+E;AAC/E,QAAQ,CAAC,OAAO,GAAG;AACnB,IAAI,qBAAqB,CAAC,CAAC,IAAI,CAAC,EAAE;AAClC,CAAC;AACD;AACA,QAAQ,CAAC,MAAM,GAAG;AAClB,IAAI,qBAAqB,CAAC,CAAC,IAAI,CAAC,EAAE;AAClC;AACA,CAAC;AACD;AACA,QAAQ,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpF,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;AAChC,YAAY,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK;AAC9B,gBAAgB,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpC,oBAAoB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9C,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,oBAAoB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI;AAClG,gBAAgB,CAAC;AACjB,gBAAgB,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACjD,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK;AAChC,gBAAgB,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpC,oBAAoB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9C,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,oBAAoB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI;AACjG,gBAAgB,CAAC;AACjB,gBAAgB,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACjD,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK;AAChC,gBAAgB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI;AAC9F,gBAAgB,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACjD,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC,KAAK;AACjC,gBAAgB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;AAC7F,gBAAgB,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACjD,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,OAAO,CAAC;AACpB,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;AACvE,gBAAgB,MAAM,CAAC,IAAI,CAAC;AAC5B,QAAQ,CAAC;AACT,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,CAAC;AACL,CAAC;AACD;AACA,QAAQ,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpF,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;AAChC,YAAY,IAAI,CAAC,EAAE,MAAM;AACzB,YAAY,IAAI,CAAC,EAAE,MAAM;AACzB,gBAAgB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;AAC1C,gBAAgB,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACjD,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,IAAI,CAAC,EAAE,KAAK,CAAC;AACzB,gBAAgB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;AAC1C,gBAAgB,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACjD,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE;AACzB,gBAAgB,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG;AACvC,gBAAgB,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACjD,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,IAAI,CAAC,GAAG,GAAG,CAAC;AACxB,YAAY,IAAI,CAAC,EAAE,GAAG,CAAC;AACvB,gBAAgB,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpC,oBAAoB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9C,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,oBAAoB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI;AAClG,gBAAgB,CAAC;AACjB,gBAAgB,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACjD,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,IAAI,CAAC,GAAG,GAAG,CAAC;AACxB,YAAY,IAAI,CAAC,EAAE,GAAG,CAAC;AACvB,gBAAgB,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpC,oBAAoB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9C,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,oBAAoB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI;AACjG,gBAAgB,CAAC;AACjB,gBAAgB,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACjD,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,IAAI,CAAC,EAAE,GAAG,CAAC;AACvB,gBAAgB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI;AAC9F,gBAAgB,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACjD,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,IAAI,CAAC,GAAG,GAAG,CAAC;AACxB,gBAAgB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;AAC7F,gBAAgB,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACjD,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,OAAO,CAAC;AACpB,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;AACvE,gBAAgB,MAAM,CAAC,IAAI,CAAC;AAC5B,QAAQ,CAAC;AACT,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,CAAC;AACL,CAAC;AACD;AACA,QAAQ,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACjC,IAAI,GAAG,CAAC,eAAe,CAAC;AACxB;AACA,IAAI,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAClE;AACA,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;AACnD,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;AAC/B,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG;AAC5B,IAAI,CAAC;AACL;AACA,IAAI,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;AAChC,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACnC,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3B,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3B,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC;AAC3C,QAAQ,oBAAoB,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACxD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AACnH,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK;AAC1B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACxG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;AACpH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5G,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACnK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACvF,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AACzH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1E,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,oBAAoB,EAAE;AAC3D;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,oBAAoB,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACvF,QAAQ,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;AAChF,QAAQ,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC5C,YAAY,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;AACjC,gBAAgB,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;AAC1E,gBAAgB,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AACpE,YAAY,EAAE;AACd,YAAY,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AAC7C,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,CAAC;AACD;AACA,QAAQ,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpC,IAAI,GAAG,CAAC,eAAe,CAAC;AACxB;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACzD,QAAQ,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;AAChF,QAAQ,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AAC/C,YAAY,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;AACjC,gBAAgB,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;AAC1E,gBAAgB,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AACpE,YAAY,EAAE;AACd,YAAY,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AAC7C,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AAC1H,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK;AACjC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACxG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;AACpH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5G,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACvF,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1E,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;AAC7C,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACnC,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3B,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa;AAC1C,IAAI,GAAG;AACP,CAAC;AACD;AACA,QAAQ,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChC,IAAI,GAAG,CAAC,eAAe,CAAC;AACxB;AACA,IAAI,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;AAC/B,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACnC,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3B,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3B,QAAQ,SAAS,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AACnC,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3B,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC;AAC3C,QAAQ,oBAAoB,CAAC,CAAC,KAAK,CAAC,oBAAoB;AACxD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AAC7G,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI;AACzB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACxG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;AACpH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5G,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;AACpH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;AAC/E,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1L,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACvF,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;AAChH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1E,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,mBAAmB,EAAE;AACzD;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,oBAAoB,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvE,QAAQ,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;AAChF,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE;AAClC,YAAY,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AAChC,YAAY,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,EAAE;AACtC,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE;AACpF;AACA,YAAY,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;AAChE,YAAY,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;AAChE;AACA,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,GAAG;AACnD,YAAY,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,oBAAoB,GAAG;AACzE;AACA,YAAY,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;AAChE,YAAY,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;AAChE;AACA,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,gBAAgB,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClC,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,gBAAgB,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,kBAAkB,EAAE;AACpJ,IAAI,CAAC;AACL,CAAC;AACD;AACA,QAAQ,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,oBAAoB,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AACvD,QAAQ,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,KAAK,CAAC,WAAW,EAAE;AAClF,QAAQ,EAAE,CAAC,CAAC,eAAe,CAAC,YAAY,CAAC,EAAE;AAC3C,YAAY,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC,CAAC;AAC3D,YAAY,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;AACrC,gBAAgB,UAAU,CAAC,CAAC,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAC1E,oBAAoB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE;AAC9C,YAAY,CAAC;AACb,YAAY,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;AACnC,gBAAgB,UAAU,CAAC,CAAC,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAC1E,oBAAoB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE;AAC9C,YAAY,CAAC;AACb,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC;AACtD,gBAAgB,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,GAAG;AAC/C,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC;AACtD,gBAAgB,GAAG,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG;AAC3E,YAAY,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE;AAC/C,QAAQ,CAAC;AACT,QAAQ,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACzC,IAAI,CAAC;AACL,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AAC3G,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG;AAC7B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACxG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;AACpH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5G,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;AAC3F,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACtM,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACvF,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1E,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;AACxC,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACnC,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3B,QAAQ,SAAS,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AACnC,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3B,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa;AAC1C,IAAI,GAAG;AACP,CAAC;AACD;AACA,QAAQ,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACjC,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AACpF,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK;AAC1B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACxG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;AACpH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AACrE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5G,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AAChO,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAClG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AACzK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;AACxK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1E,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;AACtC,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACnC,QAAQ,WAAW,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACvC,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC/B,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,oBAAoB,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC;AACzD,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC;AAC3C,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa;AAC1C,IAAI,GAAG;AACP,CAAC;AACD;AACA,QAAQ,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChC;AACA,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE;AACnD,QAAQ,EAAE,YAAY,CAAC,qBAAqB,GAAG;AAC/C,IAAI,CAAC;AACL;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AACpF,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI;AACzB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACxG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;AACpH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AACrE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5G,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AAChO,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAClG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AACzK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;AACxK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1E,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;AACrC,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACnC,QAAQ,WAAW,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACvC,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC/B,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,oBAAoB,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC;AACzD,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC;AAC3C,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa;AAC1C,IAAI,GAAG;AACP,CAAC;AACD;AACA,QAAQ,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACjC,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AAC1H,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK;AAC1B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACxG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;AACpH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AACrE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5G,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AACzK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;AACpI,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1E,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;AACtC,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACnC,QAAQ,WAAW,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACvC,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,oBAAoB,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC;AACzD,QAAQ,qBAAqB,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC;AAC3D,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa;AAC1C,IAAI,GAAG;AACP,CAAC;AACD;AACA,QAAQ,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AACzH,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO;AAC5B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACxG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;AACpH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AACrE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5G,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AACzK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;AACpI,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1E,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;AACxC,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACnC,QAAQ,WAAW,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACvC,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,oBAAoB,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC;AACzD,QAAQ,qBAAqB,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC;AAC3D,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa;AAC1C,IAAI,GAAG;AACP,CAAC;AACD;AACA,QAAQ,CAAC,uBAAuB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3C,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AAChH,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK;AACrC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACxG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;AACpH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5G,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AACrE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AACnH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5D,KAAK,CAAC,MAAM,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AAC7K,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1E,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;AACjD,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACnC,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,WAAW,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACvC,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;AAC7B,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC/B,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa;AAC1C,IAAI,GAAG;AACP,CAAC;AACD;AACA,QAAQ,CAAC,yBAAyB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7C,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AACjH,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO;AACvC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACxG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;AACpH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5G,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AACrE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AACnH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5D,KAAK,CAAC,MAAM,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AAC7K,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1E,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;AACnD,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACnC,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,WAAW,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACvC,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;AAC7B,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC/B,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa;AAC1C,IAAI,GAAG;AACP,CAAC;AACD;AACA,QAAQ,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACjC,IAAI,GAAG,CAAC,eAAe,CAAC;AACxB,QAAQ,QAAQ,CAAC;AACjB,QAAQ,YAAY,CAAC;AACrB,QAAQ,OAAO,CAAC;AAChB;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACzD,QAAQ,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;AAChF,QAAQ,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC5C,YAAY,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE;AAC1E,YAAY,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE;AAClF,YAAY,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE;AACrD,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AACvC,gBAAgB,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACrC,gBAAgB,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,YAAY,CAAC;AACb,YAAY,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE;AACxF,YAAY,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE;AACjD,YAAY,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AAC7C,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC5C,YAAY,EAAE,CAAC,KAAK,CAAC,MAAM;AAC3B,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;AAC9G,gBAAgB,KAAK,CAAC,aAAa,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE;AAC3F,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AACxG,gBAAgB,KAAK,CAAC,aAAa,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE;AACrF,YAAY,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI;AAC3G,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AAC3F,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK;AAC1B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACxG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;AACpH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;AAC/J,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC9I,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AACjI,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AAClH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AACrG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACvF,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1E,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;AACrC,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACnC,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC;AAC3C,QAAQ,UAAU,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC;AACrC,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;AAC7B,QAAQ,YAAY,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC;AACzC,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3B,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa;AAC1C,IAAI,GAAG;AACP,IAAI,EAAE,OAAO,CAAC,KAAK;AACnB,IAAI,MAAM,CAAC,KAAK,CAAC;AACjB,CAAC;AACD;AACA,QAAQ,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClC,IAAI,GAAG,CAAC,eAAe,CAAC;AACxB,QAAQ,MAAM,CAAC;AACf,QAAQ,cAAc,CAAC;AACvB,QAAQ,eAAe,CAAC;AACxB;AACA,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM;AACvH,KAAK,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI;AACpH,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE;AAC/C,IAAI,cAAc,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AAC7B,IAAI,eAAe,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC;AAC5D,IAAI,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC;AACpD,QAAQ,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,cAAc,CAAC;AAC9C;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC7D,YAAY,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;AACpF,YAAY,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACjD,gBAAgB,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;AACtE,gBAAgB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;AACrC,oBAAoB,MAAM,CAAC;AAC3B,oBAAoB,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AACxE,gBAAgB,EAAE;AAClB,gBAAgB,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACjD,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE;AAC9G,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM;AAC/B,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AAC5G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;AACxH,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAChH,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;AACtE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AAC3F,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACrE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAC3C,YAAY,OAAO,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACvC,YAAY,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACrC,YAAY,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;AACjC,YAAY,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC/B,YAAY,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa;AAC9C,QAAQ,GAAG;AACX,QAAQ,EAAE,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAC;AAC9D,YAAY,EAAE,OAAO,CAAC,KAAK;AAC3B,YAAY,MAAM,CAAC,KAAK,CAAC;AACzB,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,IAAI,IAAI,CAAC,CAAC;AACV,QAAQ,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;AAChF,QAAQ,EAAE,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAC;AAC9D,YAAY,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK;AAC3D,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,CAAC;AACD;AACA,QAAQ,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AACzC,IAAI,qBAAqB,CAAC,CAAC,IAAI,CAAC,EAAE;AAClC,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC;AACxF,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK;AAC7B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACxG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;AACpH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5G,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AAChO,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAClG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AACzK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;AACxK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1E,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC;AACzC,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACnC,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC/B,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,oBAAoB,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC;AACzD,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC;AAC3C,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa;AAC1C,IAAI,GAAG;AACP,CAAC;AACD;AACA,QAAQ,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC;AAC9C,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;AAC7C,YAAY,qBAAqB,CAAC,CAAC,IAAI,CAAC,EAAE;AAC1C,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC;AACxF,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI;AAC5B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACxG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;AACpH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5G,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AAChO,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAClG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AACzK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;AACxK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1E,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;AACxC,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACnC,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC/B,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,oBAAoB,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC;AACzD,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC;AAC3C,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa;AAC1C,IAAI,GAAG;AACP,CAAC;AACD;AACA;AACA,+EAA+E;AAC/E,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AAC5D,+EAA+E;AAC/E;AACA,QAAQ,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAChC,IAAI,UAAU,CAAC,CAAC,MAAM,CAAC,EAAE;AACzB;AACA,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM;AACvD,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5B,QAAQ,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,EAAE;AACxE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC;AACxC,IAAI,CAAC;AACL,CAAC;AACD;AACA,QAAQ,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC/B;AACA,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,WAAW,GAAG;AACpC;AACA,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC1B,QAAQ,MAAM,CAAC;AACf,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AAC5B,QAAQ,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB,CAAC,MAAM,CAAC,SAAS,EAAE;AAC/D,QAAQ,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,iBAAiB,CAAC;AACpE,QAAQ,EAAE,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC;AACvD,YAAY,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;AAC3C,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,CAAC;AACnD,gBAAgB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;AACxE,gBAAgB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;AAC5D,gBAAgB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,GAAG;AAClD,gBAAgB,QAAQ,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,KAAK,EAAE;AACtD,gBAAgB,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE;AAClD,gBAAgB,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE;AAC7C,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ;AAC1C,gBAAgB,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,GAAG;AACrD,gBAAgB,QAAQ,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE;AACrD,gBAAgB,QAAQ,CAAC,wBAAwB,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE;AACnE,YAAY,CAAC;AACb,YAAY,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,aAAa,CAAC;AAChE,YAAY,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG;AAClD,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC;AAC3D;AACA,IAAI,EAAE,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;AACzB,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG;AAC5E,SAAS,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC;AACxD,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM;AACjC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AAC5G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,GAAG;AAC7C,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE;AAChC,QAAQ,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC;AAC/E,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvD,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG;AACrE,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK;AACjC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AAC5G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE;AAC/C,QAAQ,qBAAqB,CAAC,CAAC,MAAM,CAAC,EAAE;AACxC,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;AACpF,QAAQ,SAAS,CAAC,CAAC,MAAM,CAAC,EAAE;AAC5B,QAAQ,MAAM,CAAC,aAAa,GAAG;AAC/B,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE;AAC/B,YAAY,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;AACvD,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC;AAChD;AACA,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AACvB,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG;AAChF,aAAa,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC3D,aAAa,CAAC;AACd,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS;AAC/B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AAC7C,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AAChH,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,aAAa,EAAE;AACf,YAAY,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AAC7C,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvD,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG;AACnE,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM;AAClC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AAC5G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE;AAChD;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;AACjD,YAAY,qBAAqB,CAAC,CAAC,MAAM,CAAC,EAAE;AAC5C,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC7C;AACA,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,SAAS,GAAG;AAClC,CAAC;AACD;AACA,QAAQ,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC9B,IAAI,MAAM,CAAC,WAAW,CAAC,KAAK,GAAG;AAC/B,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,GAAG;AAC1B,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG;AACxB;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC;AACvC,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ;AAC7B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACvG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1E,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE;AAC/C,CAAC;AACD;AACA,+EAA+E;AAC/E,EAAE,CAAC,UAAU,CAAC,QAAQ;AACtB,+EAA+E;AAC/E,QAAQ,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACpC,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AACvC,CAAC;AACD;AACA;AACA;AACA,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC;AAC3B,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AAC7C,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC;AACtD,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,IAAI,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE;AACzB,CAAC;AACD;AACA;AACA,QAAQ,CAAC,eAAe,EAAE,CAAC,CAAC;AAC5B,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AAC7C,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC;AAC5D,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,IAAI,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE;AACzB,CAAC;AACD;AACA;AACA,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;AACvB,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AACtC,CAAC;AACD;AACA;AACA,QAAQ,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACjC,IAAI,EAAE,qBAAqB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AAC5D,CAAC;AACD;AACA;AACA,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;AACnB,IAAI,GAAG,CAAC,WAAW,CAAC;AACpB,QAAQ,SAAS,CAAC;AAClB,QAAQ,cAAc,CAAC;AACvB;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AACtD,QAAQ,WAAW,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG;AAClC,QAAQ,SAAS,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC;AACvE,QAAQ,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;AACrF;AACA,QAAQ,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,EAAE;AAC/C,QAAQ,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACzC,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC;AACrD,QAAQ,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE;AAC7B,IAAI,CAAC;AACL,CAAC;AACD;AACA;AACA,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC;AAC3B,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC1B,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AAC1C,QAAQ,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;AAC7B,YAAY,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,QAAQ,EAAE;AACV,QAAQ,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACzC,IAAI,CAAC;AACL,CAAC;AACD;AACA;AACA,QAAQ,CAAC,eAAe,EAAE,CAAC,CAAC;AAC5B,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC1B,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AAC1C,QAAQ,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;AAC7B,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY;AACnC,QAAQ,EAAE;AACV,QAAQ,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACzC,IAAI,CAAC;AACL,CAAC;AACD;AACA;AACA,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;AACpB,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY,GAAG;AAChC,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,GAAG;AAC/B,CAAC;AACD;AACA;AACA,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;AACnB,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC1B,QAAQ,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG;AAC/B,IAAI,CAAC;AACL,CAAC;AACD;AACA;AACA,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC;AACzB,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,GAAG,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC;AACnD,QAAQ,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU;AACzC,QAAQ,IAAI,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAClC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE;AACjD,IAAI,CAAC;AACL,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM;AAC9C,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACzB,QAAQ,IAAI,CAAC,OAAO,CAAC,WAAW,GAAG;AACnC,IAAI,CAAC;AACL,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,KAAK,GAAG;AACxC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC1B,QAAQ,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACzC,IAAI,CAAC;AACL,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC;AACpE,CAAC,EAAE;AACH,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC;AACzB,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC1B,QAAQ,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,GAAG;AACvD,QAAQ,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACjC,YAAY,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC;AAC/B,QAAQ,CAAC;AACT,QAAQ,IAAI,CAAC,CAAC;AACd,YAAY,YAAY,CAAC,EAAE,CAAC,EAAE,CAAC;AAC/B,QAAQ,CAAC;AACT,QAAQ,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,YAAY,EAAE;AAChD,IAAI,CAAC;AACL,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC;AACpE,CAAC,EAAE;AACH,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;AAC1B,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC1B,QAAQ,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,GAAG;AACvD,QAAQ,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AACnC,YAAY,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,QAAQ,CAAC;AACT,QAAQ,IAAI,CAAC,CAAC;AACd,YAAY,YAAY,CAAC,EAAE,CAAC,EAAE,CAAC;AAC/B,QAAQ,CAAC;AACT,QAAQ,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,YAAY,EAAE;AAChD,IAAI,CAAC;AACL,CAAC;AACD;AACA;AACA,QAAQ,CAAC,UAAU,GAAG;AACtB,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3C,IAAI,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AAC7C,QAAQ,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;AAC5C,IAAI,CAAC;AACL,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE;AAC9B,CAAC;AACD;AACA;AACA,QAAQ,CAAC,MAAM,GAAG;AAClB,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,IAAI,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE;AAChE,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACjB,IAAI,CAAC;AACL,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE;AAC1B,CAAC;AACD;AACA;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;AC11GpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS;AACnB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK;AAC/E,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK;AACrE,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AACvE,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU;AAC3E,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AACxC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM;AAChC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,WAAW;AACrC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAC1B,CAAC,EAAE;AACH,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE;AAClC;AACA,IAAI,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACrC,QAAQ,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACrB,QAAQ,UAAU,CAAC;AACnB,QAAQ,aAAa,CAAC;AACtB;AACA,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG;AAChE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO;AAC7C,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;AACtB,QAAQ,OAAO,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AACzD,QAAQ,IAAI,CAAC,OAAO,YAAY,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAChE,QAAQ,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;AACnC,YAAY,MAAM,CAAC,WAAW,EAAE,aAAa,CAAC,SAAS,CAAC;AACxD,YAAY,cAAc,CAAC,GAAG,IAAI,CAAC;AACnC,YAAY,QAAQ,CAAC,SAAS,OAAO,CAAC,QAAQ;AAC9C,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;AAC/B,YAAY,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;AACrD,eAAe,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC;AAC5E,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;AAC3D,eAAe,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC;AAC3E,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;AACzD,eAAe,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC;AACzE,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;AACxD,eAAe,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC;AACxE,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;AACxD,eAAe,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC;AACxE,eAAe,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;AACxD,eAAe,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;AAC1D,eAAe,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9D,eAAe,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AAC5D,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,IAAI,CAAC,OAAO,YAAY,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;AACxE,QAAQ,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;AACnC,YAAY,MAAM,CAAC,WAAW,EAAE,aAAa,CAAC,IAAI,CAAC;AACnD,YAAY,cAAc,CAAC,GAAG,KAAK,CAAC;AACpC,YAAY,QAAQ,CAAC,SAAS,KAAK;AACnC,QAAQ,EAAE;AACV,IAAI,CAAC;AACL,IAAI,IAAI,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;AACzC,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE;AAC5C;AACA,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/B,QAAQ,SAAS,CAAC,KAAK,EAAE,gBAAgB,CAAC,kBAAkB;AAC5D,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;AACjB,QAAQ,OAAO,CAAC,gBAAgB,IAAI,CAAC,OAAO,CAAC;AAC7C,QAAQ,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK;AAClF,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK;AAChE,QAAQ,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;AAChE,QAAQ,aAAa,CAAC,UAAU,KAAK,CAAC;AACtC,QAAQ,eAAe,CAAC,QAAQ,KAAK,CAAC;AACtC,QAAQ,qBAAqB,CAAC,EAAE,KAAK,CAAC;AACtC,QAAQ,mBAAmB,CAAC,IAAI,KAAK,CAAC;AACtC,QAAQ,eAAe,CAAC,QAAQ,IAAI,CAAC;AACrC,QAAQ,SAAS,CAAC,cAAc,CAAC,CAAC;AAClC,QAAQ,aAAa,CAAC,UAAU,CAAC,CAAC;AAClC,QAAQ,UAAU,CAAC,aAAa,OAAO,CAAC,UAAU,CAAC;AACnD,QAAQ,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK;AACrF,QAAQ,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC;AACnC,IAAI,GAAG;AACP;AACA,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC;AACtE;AACA,IAAI,EAAE,yBAAyB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AAChD;AACA,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AACzB,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;AAC/G,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC;AACzB,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACnC,IAAI,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE;AACvG;AACA;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClE,QAAQ,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,EAAE;AACxC,YAAY,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE;AACxC,YAAY,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE;AAChE,YAAY,KAAK,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE;AACxC,YAAY,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE;AACzC,YAAY,KAAK,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtC,YAAY,KAAK,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE;AAC3C,QAAQ,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG;AAClD,IAAI,CAAC;AACL;AACA,IAAI,IAAI,CAAC,aAAa,WAAW,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AACjE,IAAI,IAAI,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE;AACtE,IAAI,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE;AACnD;AACA,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,EAAE;AACpC,QAAQ,KAAK,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE;AACzC,QAAQ,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,EAAE;AACpC,QAAQ,KAAK,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG,EAAE;AACpC,QAAQ,KAAK,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE;AACpC,QAAQ,KAAK,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE;AACvC,QAAQ,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE;AAC5D,QAAQ,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE;AACpC,QAAQ,KAAK,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE;AACpC,QAAQ,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG;AACtD,QAAQ,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,MAAM,GAAG;AACtE;AACA,QAAQ,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE;AAC5C;AACA,QAAQ,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;AAC7F,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;AAC9E,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AAC5B,QAAQ,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM;AAC9C;AACA,QAAQ,KAAK,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO;AAC/C,QAAQ,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;AAC1C,QAAQ,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC,SAAS,CAAC;AACxC,QAAQ,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC,CAAC,OAAO,EAAE;AACxC,IAAI,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG;AACrD;AACA,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,GAAG,GAAG;AAC9D,IAAI,IAAI,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,sBAAsB,EAAE;AACjF,IAAI,IAAI,CAAC,sBAAsB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,sBAAsB,EAAE;AACrE,IAAI,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AACrD,IAAI,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AACtD;AACA,IAAI,MAAM,CAAC,UAAU,CAAC;AACtB,QAAQ,IAAI,CAAC,OAAO,CAAC;AACrB,QAAQ,OAAO,CAAC,cAAc;AAC9B,IAAI,EAAE;AACN;AACA,IAAI,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,EAAE;AACzF,QAAQ,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC;AAC9D;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;AACnC,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAChD,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACvH,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AACpH,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,UAAU,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;AAC5D,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAC9F,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAC9F,YAAY,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC;AAC5C,QAAQ,CAAC;AACT,QAAQ,aAAa,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AACzD,QAAQ,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;AAC7D,IAAI,CAAC;AACL;AACA,IAAI,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAChD;AACA,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AACxC;AACA,IAAI,IAAI,CAAC,sBAAsB,CAAC,WAAW,CAAC,IAAI,CAAC,aAAa,EAAE;AAChE,IAAI,IAAI,CAAC,OAAO,CAAC,oBAAoB,EAAE,GAAG,GAAG,CAAC,EAAE,WAAW,CAAC,IAAI,CAAC,sBAAsB,EAAE;AACzF;AACA,IAAI,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;AAC9B,QAAQ,mBAAmB,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC,OAAO,EAAE;AACnE,QAAQ,mBAAmB,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,EAAE;AAC3D,QAAQ,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,OAAO,EAAE;AAC5C,IAAI,CAAC;AACL,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC;AAClC,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC/C,YAAY,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;AACnD,YAAY,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AACxC,QAAQ,MAAM,CAAC,OAAO,EAAE;AACxB,QAAQ,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7D,YAAY,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE;AACjC,QAAQ,GAAG;AACX,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG;AACjF,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,GAAG;AAChC,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,YAAY,EAAE;AAC5C,QAAQ,OAAO,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC;AACtC,QAAQ,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,EAAE;AAC1D,QAAQ,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,EAAE;AAC3D,QAAQ,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,EAAE;AAC7D,QAAQ,aAAa,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,CAAC;AAC3D,IAAI,GAAG;AACP;AACA,IAAI,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC9C,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC7B,YAAY,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE;AACxC,QAAQ,CAAC;AACT,IAAI,GAAG;AACP;AACA,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAClE,QAAQ,MAAM,CAAC,UAAU,CAAC,QAAQ,GAAG;AACrC,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,aAAa,EAAE;AAClE,YAAY,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE;AAC3D,QAAQ,EAAE,CAAC,CAAC,EAAE;AACd,IAAI,GAAG;AACP;AACA,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5D,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;AACnC,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE;AACvD,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE;AAC3C,QAAQ,CAAC;AACT,IAAI,GAAG;AACP;AACA,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE;AACjC,EAAE;AACF;AACA,EAAE,MAAM,CAAC,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG;AAC9H;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;AAC9D,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,mBAAmB,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC;AAC/H,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC7B,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC9B,YAAY,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AAC5C,oBAAoB,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;AACxF,oBAAoB,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC;AACzF,gBAAgB,EAAE;AAClB;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,gBAAgB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,EAAE;AAC5D,gBAAgB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE;AAC3C,gBAAgB,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,aAAa,CAAC;AACtD,gBAAgB,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG;AACpC,gBAAgB,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG;AAClC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;AAC/G,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC;AAC/E,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAClC;AACA,QAAQ,GAAG,CAAC,UAAU,CAAC;AACvB,YAAY,QAAQ,CAAC;AACrB,YAAY,SAAS,CAAC;AACtB,YAAY,MAAM,CAAC;AACnB,YAAY,OAAO,CAAC;AACpB,YAAY,WAAW,CAAC;AACxB;AACA,QAAQ,UAAU,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;AAC7D,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnH,YAAY,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC;AAC5C;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;AAC/D,gBAAgB,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AAC1D,gBAAgB,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AAC1D,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG;AACvF,gBAAgB,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC;AACxD,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACtE,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACvE;AACA,YAAY,EAAE,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;AACpC,gBAAgB,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;AACxD,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,UAAU,GAAG;AAC9B,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AACxC,YAAY,MAAM,MAAM,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,EAAE;AAC3D,YAAY,OAAO,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,MAAM,CAAC,UAAU,GAAG,CAAC,KAAK,EAAE;AAC3F,YAAY,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,MAAM,CAAC,cAAc,GAAG,CAAC,KAAK,CAAC;AAC9F,gBAAgB,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE;AACjD;AACA,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG;AAC5C,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;AACjD,YAAY,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AACzE;AACA,YAAY,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAC1D,YAAY,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAC1D;AACA,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE;AAC9D,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE;AAC/D,YAAY,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK;AAC9E,YAAY,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACrE,YAAY,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACtE,QAAQ,CAAC;AACT;AACA,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,aAAa;AACrC,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACtC,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB;AACA,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC;AAClD,QAAQ,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;AAChC;AACA,QAAQ,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AAClD,YAAY,OAAO,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AACtC,gBAAgB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;AACxC,gBAAgB,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC;AACxD,gBAAgB,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE;AAC3D;AACA,gBAAgB,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;AACxC,oBAAoB,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE;AACzD,gBAAgB,CAAC;AACjB;AACA,gBAAgB,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC;AACzC,oBAAoB,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE;AAC1D,gBAAgB,CAAC;AACjB;AACA,gBAAgB,QAAQ,CAAC,uBAAuB,EAAE,CAAC,CAAC;AACpD,oBAAoB,KAAK,CAAC,wBAAwB,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE;AACrE,gBAAgB,CAAC;AACjB;AACA,gBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE;AAClE,gBAAgB,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE;AAChE,gBAAgB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,YAAY,EAAE;AACpE,gBAAgB,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,uBAAuB,EAAE;AAC3F,YAAY,CAAC;AACb,QAAQ,GAAG;AACX;AACA,QAAQ,MAAM,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,GAAG;AAC5E,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,gBAAgB,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AAC3C,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG;AAC9C,QAAQ,GAAG,CAAC,IAAI,CAAC;AACjB,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACzC,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE;AAC3C,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AAC3D,gBAAgB,MAAM,CAAC,IAAI,CAAC;AAC5B,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,YAAY,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC5D,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,iBAAiB,GAAG;AACnD,QAAQ,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,GAAG,CAAC,WAAW,EAAE;AAC7D,QAAQ,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE;AACnD,QAAQ,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,WAAW,GAAG,CAAC,WAAW,EAAE;AACjE,QAAQ,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,IAAI;AAC5C,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAChD,QAAQ,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,OAAO,EAAE;AAC7C,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,wBAAwB,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAC3D,QAAQ,MAAM,CAAC,qBAAqB,CAAC,SAAS,CAAC,kBAAkB,EAAE;AACnE,IAAI,CAAC;AACL,GAAG;AACH;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,EAAE;AACH,QAAQ,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACjC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAChD,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,GAAG;AACjF,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AAChD,IAAI,CAAC;AACL,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,EAAE;AACH,QAAQ,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACjC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE;AAClC,YAAY,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AAChC,YAAY,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,QAAQ,CAAC;AACT,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;AACnC,YAAY,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC;AAChD,gBAAgB,KAAK,CAAC,KAAK;AAC3B,YAAY,CAAC;AACb,QAAQ,EAAE;AACV,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,EAAE;AAC7C,YAAY,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACpD,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,CAAC;AACD;AACA;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,EAAE;AACH,QAAQ,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC/D,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AAChD,IAAI,CAAC;AACL,CAAC;AACD;AACA;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,EAAE;AACH,QAAQ,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClC,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG;AAChI,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM;AAC9B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACxG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;AACpH,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC5G,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;AAClE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACvF,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1E,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;AACjD,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACnC,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;AAC7B,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3B,QAAQ,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa;AAC1C,IAAI,GAAG;AACP;AACA,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS;AAC/D,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS;AACtB,IAAI,MAAM,CAAC,KAAK,CAAC;AACjB,CAAC;AACD;AACA,GAAG;AACH,IAAI,CAAC,CAAC,CAAC,QAAQ;AACf,IAAI,CAAC,CAAC,CAAC,OAAO;AACd,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAC7B,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAC7B,IAAI,EAAE;AACN,QAAQ,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACjD,IAAI,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AACjE,IAAI,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AAC9D,IAAI,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AAC7D,IAAI,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AAC5D,IAAI,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AAC3D,CAAC;AACD;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;ACjfpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS;AACtC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI;AAC5E,EAAE,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS;AAChF,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC;AACvD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACZ,IAAI,MAAM,CAAC,CAAC,CAAC;AACb,QAAQ,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,GAAG;AACzE,QAAQ,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG;AAClF,QAAQ,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG;AAClF,QAAQ,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG;AAC9E,QAAQ,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjF,wBAAwB,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG;AACxD,QAAQ,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK;AAC3E,QAAQ,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACjD,IAAI,EAAE;AACN;AACA,IAAI,QAAQ,CAAC,CAAC,CAAC;AACf,QAAQ,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE;AAC3C,QAAQ,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE;AAClC,QAAQ,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE;AAClC,QAAQ,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE;AACnC,QAAQ,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE;AACpC,QAAQ,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE;AACxC,QAAQ,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE;AACtC,QAAQ,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;AACtC,IAAI,CAAC;AACL,EAAE;AACF;AACA,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG;AACzC;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC/B,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjC;AACA,QAAQ,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,MAAM;AACtC,YAAY,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC;AAC3B,YAAY,IAAI,IAAI,CAAC,CAAC,SAAS,CAAC;AAChC,YAAY,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7B,YAAY,CAAC,CAAC;AACd;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAChD,YAAY,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW;AACxC,YAAY,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG;AACtD,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACzC;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7C,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,EAAE;AACjE,YAAY,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM;AACpG,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,MAAM,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAC7D,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/D,YAAY,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACpC,gBAAgB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,gBAAgB,GAAG;AACnB,QAAQ,GAAG;AACX,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC/B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK;AACvB,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxC;AACA,QAAQ,GAAG,CAAC,KAAK,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,MAAM;AACxC,YAAY,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7B,YAAY,CAAC,CAAC;AACd;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAClD,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7C,gBAAgB,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;AAC7C,YAAY,CAAC;AACb,YAAY,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAChD,QAAQ,CAAC;AACT;AACA,QAAQ,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AACxC,IAAI,CAAC;AACL;AACA,GAAG;AACH;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;ACvHpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK;AACxB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK;AACf,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG;AAClF,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK;AACtE,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC;AAC9C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;AAC7E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;AAC7E,CAAC,EAAE;AACH,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;AAChC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACzB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;AAChC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACzB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,EAAE;AACF;AACA,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE;AAC3C,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACrB,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK;AAC/D,KAAK,EAAE;AACP,IAAI,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACvB,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AAC3C,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;AAC9D,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC;AAC7E,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG;AAC7E,KAAK,CAAC,EAAE,MAAM,CAAC,UAAU;AACzB,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7B,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AAC3B,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC7B,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AAC5B,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;AACpE,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC;AACnF,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG;AACtF,KAAK,CAAC,EAAE,MAAM,CAAC,UAAU;AACzB,KAAK,EAAE;AACP,IAAI,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AAC3B,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC7B,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AAC5B,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;AAC9D,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC;AACvE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc;AACjF,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AAC9C,KAAK,EAAE;AACP,IAAI,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC/B,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AAC3B,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AAC5B,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM;AAC3B,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;AAC5D,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC;AACrE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG;AAClF,KAAK,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AACvC,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAChC,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AAC3B,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AAC5B,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM;AAC3B,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG;AAClF,KAAK,CAAC,EAAE,MAAM,CAAC,UAAU;AACzB,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACxB,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAC/C,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;AACjF,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM;AAC1D,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,QAAQ,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;AACzB,YAAY,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7C,YAAY,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3C,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;AACzE,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;AAC7D,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;AACzF,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM;AAClE,KAAK,EAAE;AACP,IAAI,iBAAiB,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC1C,QAAQ,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,YAAY,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC5C,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;AAChF,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC;AACvE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ;AAC/E,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ;AAChC,KAAK,EAAE;AACP,IAAI,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7B,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC7D,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;AACnD,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;AAC/E,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AAClE,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC/B,QAAQ,MAAM,CAAC,CAAC;AAChB,YAAY,KAAK,CAAC,UAAU,CAAC,EAAE,KAAK;AACpC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC;AACd,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAC9B,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC;AACd,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAC9B,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK;AACnD,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK;AACtF,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC1D,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC;AAC/E,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AAC9B,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK;AAC5G,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACvC,QAAQ,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC3C,QAAQ,GAAG,CAAC,GAAG,CAAC;AAChB,QAAQ,GAAG,CAAC,GAAG,CAAC;AAChB,QAAQ,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ;AACjD,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACjC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE;AACnD,YAAY,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxB,gBAAgB,IAAI,CAAC,CAAC,CAAC;AACvB,oBAAoB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,oBAAoB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,oBAAoB,KAAK,CAAC;AAC1B,gBAAgB,IAAI,CAAC,EAAE,CAAC;AACxB,oBAAoB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,oBAAoB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,oBAAoB,KAAK,CAAC;AAC1B,gBAAgB,IAAI,CAAC,GAAG,CAAC;AACzB,oBAAoB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,oBAAoB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,oBAAoB,KAAK,CAAC;AAC1B,gBAAgB,IAAI,CAAC,GAAG,CAAC;AACzB,oBAAoB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,oBAAoB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,oBAAoB,KAAK,CAAC;AAC1B,YAAY,CAAC;AACb,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAClD,YAAY,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE;AAClC,YAAY,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE;AAClC,QAAQ,CAAC;AACT,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC9E,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC9E,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACjC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;AAC3E,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AACtC,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;AAC/D,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC1B,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI;AACrG,IAAI,CAAC;AACL,EAAE;AACF;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;ACpPpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU;AAC7B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU;AACpB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;AACxF,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG;AACjF,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC;AACxE,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;AACrE,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM;AAC/E,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ;AAC5E,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC;AAC9E,CAAC,CAAC,CAAC,EAAE,YAAY,GAAG;AACpB,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACR,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO;AAChF,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS;AACzE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE;AACtC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,WAAW;AACrC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAC1B,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,UAAU;AACvF,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;AACtF,CAAC,CAAC,MAAM,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE;AACpF,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO;AACpE,CAAC,CAAC,MAAM,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE;AAC5D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;AAChC,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC;AAC3D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,0BAA0B,CAAC;AACvD,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK;AACvE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;AACtC,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;AACzD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC;AACjD,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG;AACpF,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE;AAC9D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;AACxC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;AACrD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AAClC,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC;AAC9D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACnC,CAAC,CAAC,MAAM,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC;AAC/D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;AACrC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC;AACjF,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AACzE,CAAC,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;AAChD,CAAC,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;AACjF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;AACtC,CAAC,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC;AAClF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;AACvC,CAAC,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC;AACnF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;AACxC,CAAC,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;AAC7E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;AACrC,CAAC,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC;AAC7C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;AACrC,CAAC,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC;AAC7C,CAAC,EAAE;AACH,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACrF,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACrB;AACA,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACzB,QAAQ,OAAO,CAAC;AAChB,QAAQ,CAAC,CAAC;AACV;AACA,IAAI,EAAE,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AACnC,QAAQ,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AACxB,IAAI,CAAC,IAAI,CAAC;AACV,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC;AACnB,YAAY,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AAC3B,YAAY,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AAC5B,YAAY,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AAC9B,YAAY,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACjC,YAAY,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AAC9B,YAAY,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7B,QAAQ,EAAE;AACV,IAAI,CAAC;AACL;AACA,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU;AAClF,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC;AAC1D,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/B;AACA,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AAC5D,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY;AAC7D,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI;AAC9D,IAAI,EAAE,MAAM;AACZ,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE;AACpC;AACA,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AACxB,QAAQ,EAAE,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ;AACpF,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAClD,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,gBAAgB,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9C,gBAAgB,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW;AACnD,gBAAgB,KAAK,CAAC;AACtB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AACvB,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACtD,YAAY,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE;AACnC,QAAQ,CAAC,CAAC,EAAE;AACZ,IAAI,CAAC;AACL;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM;AAC/B,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AACnC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC;AAC1C,KAAK,EAAE;AACP,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE;AAC3E,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,UAAU;AAC/C,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC;AAC1C,KAAK,EAAE;AACP,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC;AAC1E,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AACnC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC;AAC1C,KAAK,EAAE;AACP,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC;AACrF,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAChC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC;AAC1C,KAAK,EAAE;AACP,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC;AACrF,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAChC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC;AAC1C,KAAK,EAAE;AACP,IAAI,GAAG;AACP,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK;AAC9B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC;AAC1C,KAAK,EAAE;AACP;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC/C,QAAQ,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AAChC,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACnB,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE;AACxE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK;AACtD,QAAQ,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,QAAQ,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE;AACjD,QAAQ,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7B,QAAQ,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,QAAQ,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,QAAQ,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7B,QAAQ,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7B,QAAQ,IAAI,CAAC,KAAK,OAAO,CAAC,CAAC,KAAK,CAAC;AACjC,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK;AAC3D,QAAQ,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC;AACpC,QAAQ,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;AACtC;AACA,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ;AACA,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW;AACnE,QAAQ,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM;AAChD,QAAQ,IAAI,CAAC,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC;AAChC,QAAQ,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AAC9D,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,QAAQ,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;AACxE;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AAC7B,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;AAC/D,YAAY,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;AACjC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;AACjC,gBAAgB,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AAChF,gBAAgB,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;AACpG,gBAAgB,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AACjD,gBAAgB,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;AACtC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;AAClC,gBAAgB,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS;AAC/D,gBAAgB,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;AACnD,gBAAgB,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;AACvC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AACzE,QAAQ,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,QAAQ,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC5F,YAAY,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAChC,gBAAgB,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;AAChE,oBAAoB,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3E,oBAAoB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACjC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;AACrB,YAAY,EAAE;AACd,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AAC3D,YAAY,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE;AACjC,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA,EAAE;AACF;AACA,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE;AAChD,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC1B;AACA,IAAI,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC;AACxB,YAAY,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC;AACvD,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,OAAO,CAAC;AAClF,QAAQ,EAAE;AACV,QAAQ,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;AAC/B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC9C,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM;AACxF,KAAK,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO;AACtF,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC;AACnC,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,EAAE;AACP,IAAI,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACrC,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;AAC/B,YAAY,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE;AAC3C,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;AAC/B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC/C,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM;AACzF,KAAK,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO;AACtF,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC;AACpC,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACtC,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;AAChC,YAAY,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE;AAC3C,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC;AAChC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACtC;AACA,QAAQ,EAAE,CAAC,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE;AACvE,QAAQ,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,cAAc,CAAC,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,QAAQ;AAC7E,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,cAAc;AACvC,QAAQ,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG;AACjC,YAAY,CAAC,CAAC;AACd,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;AAC9C,YAAY,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACtE,QAAQ,CAAC;AACT,QAAQ,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE;AAChD,YAAY,MAAM,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,EAAE;AAC7C,QAAQ,EAAE;AACV,QAAQ,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3C,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,EAAE;AACP,IAAI,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpC,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,EAAE;AAChD,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE;AAClF,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE;AACnF;AACA,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACnC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACtC,QAAQ,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AACnF,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;AACzC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;AACzC;AACA,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE;AACnC,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;AACtG,KAAK,EAAE;AACP,IAAI,eAAe,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACjC,QAAQ,GAAG,CAAC,CAAC,CAAC;AACd,YAAY,KAAK,CAAC;AAClB;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI;AAC7D,YAAY,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE;AACxC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7C,gBAAgB,KAAK,CAAC;AACtB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,KAAK,EAAE;AACP,IAAI,cAAc,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5C,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACxD,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;AAC5D,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI;AACvG;AACA,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE;AACxE,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;AAC3C,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;AAC3C;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,GAAG;AAC9D,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,GAAG;AAC/D;AACA,QAAQ,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;AAC1E,QAAQ,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM;AACjD,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,QAAQ,CAAC;AACT,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC5B,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACxD,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACjC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,QAAQ,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AACpF,YAAY,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE;AACjD,YAAY,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE;AACnD,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;AACpE,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;AACrE,YAAY,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;AACpE,YAAY,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;AACrE,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAC7C;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;AACrD,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;AACrD;AACA,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE;AAC5E,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AAClD,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC;AACnE,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG;AAC1B,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;AACtB,KAAK,EAAE;AACP,IAAI,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACnC,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,YAAY,YAAY,CAAC;AACzB,YAAY,QAAQ,CAAC;AACrB,YAAY,WAAW,CAAC;AACxB,YAAY,OAAO,CAAC;AACpB,YAAY,QAAQ,CAAC;AACrB,YAAY,QAAQ,CAAC;AACrB,YAAY,OAAO,CAAC;AACpB;AACA;AACA,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACnB,YAAY,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE;AACxC,YAAY,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACvD,YAAY,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,EAAE;AACnD,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjC,gBAAgB,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE;AAC/E,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE;AACpC,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7C,gBAAgB,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE;AAC1C,YAAY,CAAC;AACb,YAAY,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE;AAC7E,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;AACjC,gBAAgB,GAAG;AACnB,iBAAiB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;AACpE,iBAAiB,CAAC;AAClB,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM;AACrC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU;AACrD,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACjC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3H,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAC7C,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AAC5C,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AACtF,iBAAiB,EAAE;AACnB,gBAAgB,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AACzG,gBAAgB,MAAM,CAAC;AACvB,YAAY,CAAC;AACb;AACA,YAAY,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG;AACnF,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AAC5D,gBAAgB,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC;AACxE,YAAY,CAAC;AACb;AACA,YAAY,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AACrD,YAAY,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC;AAClE,aAAa,CAAC;AACd,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK;AAC3B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU;AACjD,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACvH,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU;AAC5C,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,aAAa,EAAE;AACf,YAAY,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE;AACrE,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE;AACjC,YAAY,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AAC9E,YAAY,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG;AAC7E,YAAY,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC;AACzE,YAAY,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,MAAM,GAAG,GAAG,OAAO,GAAG,EAAE,EAAE,CAAC,IAAI;AACnE,YAAY,EAAE,KAAK,EAAE;AACrB,gBAAgB,GAAG,CAAC,CAAC,GAAG,CAAC;AACzB,gBAAgB,KAAK,CAAC,CAAC,KAAK,CAAC;AAC7B,gBAAgB,YAAY,CAAC,CAAC,YAAY,CAAC;AAC3C,gBAAgB,QAAQ,CAAC,CAAC,QAAQ;AAClC,YAAY,GAAG;AACf,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC;AACnD,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC;AAChC,gBAAgB,GAAG,CAAC,CAAC,GAAG,CAAC;AACzB,gBAAgB,eAAe,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC;AAC1D,gBAAgB,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;AAC1C,gBAAgB,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC1C,oBAAoB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,EAAE;AACtD,oBAAoB,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE;AACrC,gBAAgB,EAAE;AAClB,gBAAgB,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC9C,oBAAoB,GAAG,CAAC,GAAG,CAAC;AAC5B;AACA,oBAAoB,EAAE;AACtB,wBAAwB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO;AAChH,wBAAwB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ;AAC/G,wBAAwB,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM;AACpG,qBAAqB,EAAE;AACvB,oBAAoB,GAAG,CAAC,CAAC;AACzB,wBAAwB,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE;AACtF,oBAAoB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,wBAAwB,GAAG,CAAC,YAAY,CAAC;AACzC,wBAAwB,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC9E,4BAA4B,YAAY,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE;AAC3D,wBAAwB,CAAC,CAAC,IAAI,CAAC,CAAC;AAChC,4BAA4B,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,GAAG;AAC1D,wBAAwB,CAAC;AACzB;AACA,wBAAwB,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE;AAC9E,oBAAoB,CAAC;AACrB;AACA,oBAAoB,IAAI;AACxB,qBAAqB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;AACxE,qBAAqB,CAAC;AACtB,qBAAqB,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM;AACzC,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU;AACzD,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrC,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC/H,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AACjD,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AAChD,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1F,qBAAqB,EAAE;AACvB,oBAAoB,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AACtD,wBAAwB,OAAO,CAAC,CAAC,GAAG,CAAC;AACrC,wBAAwB,MAAM,CAAC,CAAC,GAAG;AACnC,oBAAoB,GAAG;AACvB,gBAAgB,CAAC;AACjB,YAAY,GAAG;AACf,QAAQ,CAAC;AACT;AACA,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG;AAC1E,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG;AAC5E,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE;AAC3E,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,IAAI;AACzE,KAAK,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE;AAC1E,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;AAChF,KAAK,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC;AACzD,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI;AACjD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM;AACxD,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AACxB,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACrC,QAAQ,MAAM,CAAC,KAAK,CAAC;AACrB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG;AAClD,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC;AACnE,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK;AAChF,KAAK,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI;AAC3E,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK;AACzE,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC;AAC/D,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI;AACjD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM;AACxD,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU;AAC9E,KAAK,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;AACvD,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;AACtB,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACtC,QAAQ,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,EAAE;AACrD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG;AAC5E,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC;AAChE,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK;AAChF,KAAK,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI;AAC3E,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK;AACzE,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC;AAC/D,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;AACtB,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,QAAQ,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,EAAE;AACrD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG;AACjG,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC;AAChE,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,iBAAiB,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;AACtG,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC;AACnG,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AAC/F,KAAK,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE;AACjC,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;AACxB,KAAK,EAAE;AACP,IAAI,kBAAkB,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,QAAQ,MAAM,CAAC,GAAG;AAClB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACjD,QAAQ,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AACxC,eAAe,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AACxC,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACxB,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACxB,eAAe,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;AAChC,eAAe,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC9B,IAAI,CAAC;AACL,EAAE;AACF;AACA;AACA,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,EAAE;AAClE;AACA;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI;AAC5E,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI;AACX,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO;AAC9D,CAAC,EAAE;AACH,QAAQ,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,EAAE;AAChC,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;AACxC,QAAQ,MAAM,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AAClC,QAAQ,UAAU,CAAC;AACnB,QAAQ,IAAI,CAAC;AACb;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACjB,QAAQ,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AAC5D,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,QAAQ,MAAM,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;AAChC,QAAQ,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACxC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;AACzB,YAAY,GAAG,CAAC,UAAU,CAAC;AAC3B,QAAQ,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;AAC9E,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE;AACvC,QAAQ,GAAG,CAAC;AACZ,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AACvE,YAAY,GAAG,CAAC,WAAW,CAAC,CAAC;AAC7B,YAAY,EAAE,QAAQ,CAAC,CAAC,YAAY,CAAC,EAAE;AACvC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AACpB,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;AACpC,QAAQ,CAAC;AACT,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC,WAAW,CAAC,EAAE;AAClD,QAAQ,GAAG,CAAC;AACZ,UAAU,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,YAAY,EAAE;AAC3C,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AACnB,UAAU,IAAI,CAAC,CAAC,EAAE,YAAY,CAAC;AAC/B,QAAQ,CAAC;AACT,IAAI,CAAC,IAAI,CAAC;AACV,QAAQ,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC;AAC5B,IAAI,CAAC;AACL,IAAI,MAAM,CAAC,IAAI,CAAC;AAChB,CAAC;AACD;AACA;AACA,GAAG;AACH,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,aAAa;AAC7E,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC;AAChE,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM;AAC7E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG;AAC/E,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC;AAC5B,CAAC,EAAE;AACH,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE;AAC/D,IAAI,GAAG,CAAC,QAAQ,CAAC;AACjB,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,aAAa,CAAC,EAAE;AACrC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,IAAI,UAAU,GAAG,CAAC,EAAE;AAC9C,YAAY,EAAE,UAAU,CAAC,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACxD,YAAY,EAAE,UAAU,CAAC,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;AAC3E,YAAY,aAAa,CAAC,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;AACtF,QAAQ,EAAE;AACV,YAAY,MAAM,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,EAAE;AAC7C,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE;AACzE,EAAE;AACF;AACA;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;AC/qBpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa;AAChC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa;AACvB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,UAAU;AACpC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS;AAC/E,CAAC,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;AACrE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AACzB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC3B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AAC9B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC3B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU;AAC7B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,WAAW,GAAG,CAAC,YAAY;AACpD,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC9B,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU;AAChC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,WAAW,GAAG,CAAC,YAAY;AACvD,CAAC,EAAE;AACH,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC5H,IAAI,GAAG,CAAC,CAAC,CAAC;AACV,QAAQ,IAAI,CAAC;AACb,QAAQ,KAAK,CAAC;AACd,QAAQ,OAAO,CAAC;AAChB;AACA,IAAI,EAAE,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AACnC,QAAQ,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AACxB,IAAI,CAAC,IAAI,CAAC;AACV,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC;AACnB,YAAY,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;AAClC,YAAY,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;AACnC,YAAY,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;AACrC,YAAY,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;AACxC,YAAY,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;AACrC,YAAY,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;AACvC,YAAY,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;AACzC,YAAY,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;AACrC,YAAY,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,QAAQ,EAAE;AACV,IAAI,CAAC;AACL;AACA,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,GAAG;AAC3B,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;AACzC,IAAI,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;AAC3C,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;AAC7C;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AAC9B,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/D,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE;AAC1C,YAAY,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5E,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,IAAI,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;AACnD,gBAAgB,CAAC;AACjB,gBAAgB,IAAI,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACvD,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AAC5C;AACA,EAAE;AACF;AACA,EAAE,MAAM,CAAC,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,aAAa,CAAC,SAAS,CAAC,GAAG;AACjH;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE;AAC/E,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI;AACjC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG;AACrC,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE;AACpC,QAAQ,GAAG,CAAC,EAAE,CAAC;AACf,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3B,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;AAClC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;AAC3C,YAAY,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;AACvG,gBAAgB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC;AACvD,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,WAAW,GAAG;AACtC;AACA,QAAQ,MAAM,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;AAC3E,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AACtE,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa;AAC/D,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC;AACxE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU;AAC9E,KAAK,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;AACvD,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE;AACrC;AACA,QAAQ,GAAG,CAAC,OAAO,CAAC;AACpB;AACA,QAAQ,EAAE,CAAC,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,EAAE;AACrC;AACA,YAAY,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACrD;AACA,QAAQ,CAAC,IAAI,CAAC;AACd;AACA,YAAY,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACxD,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;AACvC,YAAY,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AAC3C,oBAAoB,cAAc,GAAG,CAAC,GAAG,CAAC,EAAE,qBAAqB,CAAC,EAAE,OAAO,IAAI;AAC/E;AACA,YAAY,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,gBAAgB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,SAAS;AACxD,YAAY,CAAC,IAAI,CAAC;AAClB,gBAAgB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG;AACzC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,OAAO,CAAC;AACvB,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,QAAQ,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE;AAC3G,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC9C,YAAY,IAAI,CAAC;AACjB,YAAY,KAAK,CAAC;AAClB,YAAY,IAAI,CAAC;AACjB,YAAY,IAAI,CAAC;AACjB,YAAY,IAAI,CAAC;AACjB,YAAY,IAAI,CAAC;AACjB,YAAY,CAAC,CAAC;AACd;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACxC,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACnD,YAAY,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9B;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACnE,gBAAgB,QAAQ,CAAC;AACzB,YAAY,CAAC;AACb;AACA,YAAY,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,EAAE;AAChD,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAClC,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAClC,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7C,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;AAC9C;AACA,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;AACxD,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU;AAC3G,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;AACvD,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;AACvD;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACnE,gBAAgB,MAAM,CAAC,IAAI,CAAC;AAC5B,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,KAAK,CAAC;AACrB,IAAI,CAAC;AACL,GAAG;AACH;AACA;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,EAAE;AACH,QAAQ,CAAC,gBAAgB,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,EAAE;AAChD;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAC/C,QAAQ,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;AACvD,IAAI,CAAC;AACL;AACA,IAAI,GAAG,CAAC,IAAI,WAAW,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC;AAChD,QAAQ,QAAQ,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;AACxD,QAAQ,EAAE,aAAa,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC;AAC7D,QAAQ,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC;AAC9B,QAAQ,YAAY,GAAG,CAAC,CAAC,GAAG;AAC5B,QAAQ,aAAa,CAAC;AACtB,QAAQ,YAAY,CAAC;AACrB,QAAQ,QAAQ,CAAC;AACjB,QAAQ,QAAQ,CAAC;AACjB,QAAQ,CAAC,CAAC;AACV;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAChC;AACA,QAAQ,GAAG,CAAC,CAAC;AACb,YAAY,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AAC/D,YAAY,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AACzC,gBAAgB,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACzE,YAAY,CAAC;AACb;AACA,YAAY,aAAa,CAAC,CAAC,CAAC,CAAC;AAC7B,gBAAgB,KAAK,CAAC,CAAC,CAAC;AACxB,oBAAoB,KAAK,CAAC,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE;AAC9E,oBAAoB,GAAG,CAAC,SAAS,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAC5D,oBAAoB,MAAM,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AAC/D,oBAAoB,WAAW,CAAC,CAAC,IAAI,CAAC;AACtC,oBAAoB,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAChF,oBAAoB,QAAQ,CAAC,IAAI,QAAQ,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACjF,oBAAoB,IAAI,CAAC,CAAC,CAAC;AAC3B,wBAAwB,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAClF,wBAAwB,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAChF,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB,YAAY,EAAE;AACd;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,GAAG,oBAAoB,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1E,gBAAgB,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;AAChC,oBAAoB,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;AACjG,gBAAgB,EAAE;AAClB,YAAY,CAAC;AACb;AACA,YAAY,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC,EAAE;AACtE,YAAY,EAAE,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AAC9C,gBAAgB,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACrF,YAAY,CAAC;AACb;AACA,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC1D,gBAAgB,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE;AAClD,gBAAgB,QAAQ,KAAK,CAAC,CAAC,YAAY,CAAC,oBAAoB,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AAC/E,gBAAgB,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AAC7C,oBAAoB,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACrF,gBAAgB,CAAC;AACjB;AACA,gBAAgB,YAAY,CAAC,IAAI,EAAE;AACnC,oBAAoB,IAAI,CAAC,CAAC,CAAC;AAC3B,wBAAwB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACxE,wBAAwB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACxE,wBAAwB,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAChF,wBAAwB,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAClF,wBAAwB,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAC1F,wBAAwB,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACzF,oBAAoB,CAAC;AACrB,gBAAgB,GAAG;AACnB,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE;AACtC,gBAAgB,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC;AAC/D,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,mBAAmB,CAAC,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC,EAAE;AACpE;AACA,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvB,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;AACxC,gBAAgB,CAAC,CAAC,CAAC;AACnB,gBAAgB,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE;AACvD,QAAQ,CAAC;AACT,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,QAAQ,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;AACvD,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,CAAC,EAAE;AAClE,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC,SAAS,CAAC;AACvD,QAAQ,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE;AACjC,IAAI,CAAC;AACL;AACA,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;AACnD,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,EAAE;AACH,QAAQ,CAAC,mBAAmB,CAAC,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC,EAAE;AAC1D,IAAI,GAAG,CAAC,SAAS,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AAC5C,QAAQ,QAAQ,MAAM,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC;AACtC,QAAQ,UAAU,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC;AACzC,QAAQ,QAAQ,MAAM,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC;AACvC,QAAQ,YAAY,EAAE,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG;AACpD,QAAQ,KAAK,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE;AACvD,QAAQ,MAAM,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE;AACxD,QAAQ,QAAQ,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE;AAC3D,QAAQ,WAAW,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE;AAC1D,QAAQ,YAAY,EAAE,CAAC,CAAC,GAAG;AAC3B,QAAQ,QAAQ,CAAC;AACjB,QAAQ,CAAC,CAAC;AACV;AACA,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa;AAC9E,IAAI,EAAE,MAAM,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG;AAC5E,IAAI,EAAE,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG;AAC9E,IAAI,EAAE,MAAM,KAAK,CAAC,MAAM,CAAC;AACzB,IAAI,EAAE;AACN,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AAClD,IAAI,EAAE;AACN,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,QAAQ,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;AACxB,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;AACzE,QAAQ,EAAE;AACV,IAAI,GAAG;AACP;AACA,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACjD,QAAQ,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;AAC1C;AACA,QAAQ,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC;AAC7C,YAAY,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;AACvC,YAAY,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;AACvC,YAAY,QAAQ,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE;AAC3C,YAAY,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE;AAC5C,YAAY,QAAQ,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE;AAC9C,YAAY,QAAQ,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC;AAC7C,QAAQ,GAAG;AACX,IAAI,CAAC;AACL;AACA,IAAI,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3B,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE;AAC3C,QAAQ,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE;AAC9C,QAAQ,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE;AACpD,QAAQ,WAAW,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,EAAE;AAC7D,QAAQ,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE;AACtC,QAAQ,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE;AACtC,QAAQ,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE;AAC1C,QAAQ,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE;AAChD,QAAQ,YAAY,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE;AACrD,IAAI,EAAE,CAAC,aAAa,CAAC,EAAE;AACvB;AACA,CAAC;AACD;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;ACpXpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,cAAc;AACjC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc;AACxB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,gBAAgB,CAAC,SAAS;AAC3F,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,UAAU;AACpC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AACjC,CAAC,EAAE;AACH,EAAE,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE;AACvC;AACA,IAAI,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;AAClC;AACA,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE;AACpC;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,QAAQ,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,EAAE;AACpE,IAAI,CAAC;AACL;AACA,IAAI,OAAO,CAAC,sBAAsB,CAAC,CAAC,CAAC,GAAG;AACxC;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC,YAAY;AACrD,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAChD,QAAQ,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;AAC5C,QAAQ,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;AAC9C,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACnC,QAAQ,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;AAC3C,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACpC,QAAQ,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;AAC5C,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ;AAC/B,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,YAAY,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;AACrD,YAAY,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;AACnF,YAAY,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;AAC7E,YAAY,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC;AAC5D,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM;AACtD,YAAY,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG;AACpC,YAAY,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC1D,gBAAgB,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAChF,oBAAoB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,EAAE,EAAE;AACrE,oBAAoB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE;AACzD,oBAAoB,OAAO,CAAC,sBAAsB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,wBAAwB,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;AACnD,wBAAwB,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK;AAC3E,oBAAoB,EAAE;AACtB,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AAClF,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AAC3D,YAAY,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE;AAC3C,YAAY,YAAY,CAAC,CAAC,CAAC,GAAG;AAC9B;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACxD,YAAY,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC/C,gBAAgB,YAAY,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE;AACpD,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxC,YAAY,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,EAAE;AACpE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;AAClE,YAAY,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;AACxC,QAAQ,CAAC;AACT,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,QAAQ,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3G,QAAQ,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,GAAG;AACnG,QAAQ,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;AAC9D,QAAQ,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9C;AACA,QAAQ,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,EAAE;AACjD,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK;AACzD,QAAQ,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAClC,YAAY,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;AACrE,YAAY,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;AACvE,YAAY,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AAChE,YAAY,WAAW,CAAC,CAAC,CAAC,CAAC;AAC3B,YAAY,QAAQ,CAAC,CAAC,CAAC,CAAC;AACxB,YAAY,QAAQ,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC/C,QAAQ,GAAG;AACX,QAAQ,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACrC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,GAAG;AACrF,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC;AAC/D,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;AAClC,YAAY,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI;AACjG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG;AACnG,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AAC5C,EAAE;AACF;AACA,EAAE,MAAM,CAAC,CAAC,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,cAAc,CAAC,SAAS,CAAC,GAAG;AACnH,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE;AAC/E,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI;AACjC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG;AACrC,KAAK,EAAE;AACP;AACA,IAAI,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACrC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ;AACnC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;AAC3E,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACtB,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;AACzC,YAAY,IAAI,GAAG,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE;AAChG,YAAY,IAAI,GAAG,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9E,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI;AACzG,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB;AACA,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACtB,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AACnC,YAAY,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACvG,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACpE,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE;AAC3C,YAAY,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE;AACrD,YAAY,CAAC,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC/D,gBAAgB,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAC;AACpD,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB;AACA,QAAQ,EAAE,CAAC,GAAG,CAAC,IAAI;AACnB,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,MAAM,CAAC,KAAK,CAAC;AACzB,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa;AACnD,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC;AAChE,KAAK,CAAC,CAAC,CAAC;AACR,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE;AACpF,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;AACvF,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACxB,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACvC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7B,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9B,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AACtC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AAC5C,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;AAC5F,KAAK,CAAC,CAAC,CAAC;AACR,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE;AACrC,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM;AAClE,QAAQ,EAAE,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,YAAY,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,EAAE;AACrD,YAAY,OAAO,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE;AAC9E,YAAY,OAAO,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI;AAC1D,YAAY,MAAM,CAAC,OAAO,CAAC;AAC3B,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;AACzC,YAAY,IAAI,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE;AAC3E,YAAY,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI;AACxD,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,EAAE;AACP,IAAI,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACrC;AACA,QAAQ,EAAE,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC;AAC5C,YAAY,MAAM,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE;AACzE,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,EAAE;AAC7D;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,WAAW,EAAE,CAAC,CAAC;AACtF,YAAY,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,WAAW,EAAE,KAAK,CAAC;AAClE,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;AAC/B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;AACjD,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACtC;AACA,QAAQ,EAAE,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC;AAC5C,YAAY,MAAM,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE;AAC1E,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,EAAE;AAC7D;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,WAAW,EAAE,CAAC,CAAC;AACtF,YAAY,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,WAAW,EAAE,MAAM,CAAC;AACnE,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC;AAChC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACvC;AACA,QAAQ,EAAE,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC;AAC5C,YAAY,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC;AACjC,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC7F,gBAAgB,UAAU,CAAC,CAAC;AAC5B,oBAAoB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAC9C,oBAAoB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC;AACrD,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,UAAU,CAAC;AAC9B,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE;AACtE,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,EAAE;AACP,IAAI,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpC;AACA,QAAQ,EAAE,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC;AAC5C,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE;AAClD,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACxB,gBAAgB,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACzC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACzC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE;AACpE,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,KAAK,EAAE;AACP,IAAI,cAAc,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9C;AACA,QAAQ,EAAE,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC;AAC5C,YAAY,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACrC,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE;AAC9E,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG;AAC5E,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC;AAChE,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK;AACtC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;AACtB,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACxC;AACA,QAAQ,EAAE,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC;AAC5C,YAAY,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3B,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC/F,gBAAgB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC;AAC/C,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,GAAG,CAAC;AACvB,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,SAAS;AACrB,QAAQ,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAChC,YAAY,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;AACnD,YAAY,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3D;AACA,YAAY,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK;AAC9C,YAAY,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE;AACzD,YAAY,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3D;AACA,YAAY,IAAI,CAAC,IAAI,CAAC,MAAM;AAC5B,YAAY,SAAS,CAAC;AACtB,YAAY,UAAU,CAAC;AACvB,YAAY,iBAAiB,CAAC;AAC9B,YAAY,kBAAkB,CAAC;AAC/B,YAAY,UAAU,CAAC;AACvB,YAAY,SAAS,CAAC;AACtB,YAAY,SAAS,CAAC;AACtB,YAAY,SAAS,CAAC;AACtB,YAAY,SAAS,CAAC;AACtB,YAAY,QAAQ,CAAC;AACrB,YAAY,WAAW,CAAC;AACxB,YAAY,GAAG,CAAC;AAChB;AACA,QAAQ,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE;AAC7C,QAAQ,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE;AAC/C,QAAQ,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3D,QAAQ,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE;AAC7D;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,OAAO,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAClE,aAAa,IAAI,GAAG,OAAO,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAClE,aAAa,IAAI,GAAG,OAAO,GAAG,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,YAAY,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE;AACvC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;AACxC,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE;AAClE,YAAY,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI;AACxC,YAAY,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AAChC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC;AAC9C,YAAY,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC;AAC/C,YAAY,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE;AAC9E,YAAY,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE;AAChF,YAAY,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;AAC5D,YAAY,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE;AACpF,QAAQ,CAAC;AACT,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE;AAC5F;AACA,QAAQ,MAAM,CAAC,GAAG,CAAC;AACnB,IAAI,CAAC;AACL;AACA,EAAE,GAAG;AACL;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO;AACrG,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM;AACpD,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;AACtB,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACpC,QAAQ,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AAC9B,YAAY,CAAC,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE;AAChF,YAAY,CAAC,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE;AACpF,YAAY,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;AACpD,QAAQ,EAAE;AACV,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AAClE,QAAQ,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AAC/D,IAAI,CAAC;AACL;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AACzD,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ;AACzC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;AACtB,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;AACvC,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG;AACxB,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACvD,YAAY,MAAM,CAAC,IAAI,EAAE;AACzB,gBAAgB,GAAG,CAAC,CAAC,OAAO,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;AAC5F,gBAAgB,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;AAC9C,gBAAgB,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM;AAC/C,YAAY,GAAG;AACf,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3C,YAAY,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AACrC,QAAQ,GAAG;AACX,IAAI,CAAC;AACL;AACA;AACA,IAAI,QAAQ,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;AACzC,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG;AACvB,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AACnD,YAAY,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;AAC3D,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,IAAI,YAAY,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC;AACrD,YAAY,QAAQ,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AAC3C,YAAY,aAAa,GAAG,CAAC,CAAC,IAAI,CAAC;AACnC;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,YAAY,GAAG,CAAC,CAAC;AACjB,gBAAgB,aAAa,CAAC,CAAC,CAAC,GAAG;AACnC,gBAAgB,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,EAAE;AAClD,gBAAgB,MAAM,CAAC,aAAa,CAAC;AACrC;AACA,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,gBAAgB,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5C,oBAAoB,CAAC,CAAC,CAAC;AACvB,oBAAoB,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE;AAC5D,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,QAAQ,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;AACxD,IAAI,CAAC;AACL;AACA,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC1D,QAAQ,GAAG,CAAC,CAAC,CAAC;AACd,YAAY,KAAK,CAAC;AAClB,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI;AAC1D,YAAY,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG;AAC1C,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,MAAM;AACtC,gBAAgB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE;AACxC,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;AAC7C,gBAAgB,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAClD,YAAY,CAAC,IAAI,CAAC;AAClB,gBAAgB,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9D,oBAAoB,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;AAC9E,gBAAgB,CAAC;AACjB,gBAAgB,aAAa,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE;AACxD,YAAY,CAAC;AACb,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACxC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;AAC1D,gBAAgB,UAAU,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AACjF,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA;AACA;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;AC3cpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa;AAChC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,EAAE;AACF,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO;AAC1E,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;AAC5E,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,EAAE;AAClE,CAAC,EAAE;AACH;AACA;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa;AACvB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,aAAa,EAAE,EAAE,EAAE,EAAE,CAAC;AACpE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,IAAI;AACjF,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE;AAClF,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAC/E,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;AAC5C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI;AACrD,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,oBAAoB,CAAC,WAAW,CAAC;AACxE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO;AAC1E,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG;AAC1E,CAAC,CAAC,CAAC,MAAM,CAAC;AACV,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,UAAU;AACpC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS;AAC/E,CAAC,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;AACrE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AACzB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC3B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AAC9B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC3B,CAAC,EAAE;AACH,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC9E,IAAI,GAAG,CAAC,OAAO,CAAC;AAChB;AACA,IAAI,EAAE,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AACnC,QAAQ,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AACxB,IAAI,CAAC,IAAI,CAAC;AACV,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC;AACnB,YAAY,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AAChC,YAAY,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACjC,YAAY,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACnC,YAAY,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACtC,YAAY,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAClC,QAAQ,EAAE;AACV,IAAI,CAAC;AACL,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO;AACtE,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ;AACzE,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ;AACnE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;AAC5C,QAAQ,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AACjC,QAAQ,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClC,IAAI,CAAC;AACL,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;AAC5B,QAAQ,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC;AAC/B,QAAQ,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AAChC,IAAI,CAAC;AACL,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;AAC5B,QAAQ,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,GAAG;AAC5D,IAAI,CAAC;AACL,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACzB;AACA,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AAC5C;AACA,EAAE;AACF;AACA,EAAE,MAAM,CAAC,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,aAAa,CAAC,SAAS,CAAC,GAAG;AACjH;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE;AAC/E,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI;AACjC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG;AACrC,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE;AACpC,QAAQ,MAAM,CAAC,CAAC;AAChB,YAAY,IAAI,CAAC,IAAI,CAAC,EAAE;AACxB,YAAY,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI;AACzC,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa;AACnD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC;AACxE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU;AAC9E,KAAK,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;AACvD,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE;AACrC,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,QAAQ,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE;AACxE,IAAI,CAAC;AACL,GAAG;AACH;AACA;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;AChJpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa;AAChC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,EAAE;AACF,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO;AAC1E,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;AAC5E,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,EAAE;AAClE,CAAC,EAAE;AACH;AACA;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa;AACvB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE;AACvE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AACnD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,UAAU;AACpC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS;AAC/E,CAAC,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;AACrE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AACzB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC3B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AAC9B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC3B,CAAC,EAAE;AACH,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC9E,IAAI,GAAG,CAAC,OAAO,CAAC;AAChB;AACA,IAAI,EAAE,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AACnC,QAAQ,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AACxB,IAAI,CAAC,IAAI,CAAC;AACV,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC;AACnB,YAAY,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AAChC,YAAY,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACjC,YAAY,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACnC,YAAY,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACtC,YAAY,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAClC,QAAQ,EAAE;AACV,IAAI,CAAC;AACL,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM;AACxE,IAAI,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AACxC,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAC7D,QAAQ,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAC/D,QAAQ,GAAG,CAAC;AACZ;AACA,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO;AACnD,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;AACzC,QAAQ,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC;AAClC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC;AACnC,IAAI,CAAC;AACL,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAClE,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC;AAC3B,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC;AAClC,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC;AACpC;AACA,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AAC5C;AACA,EAAE;AACF;AACA,EAAE,MAAM,CAAC,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,aAAa,CAAC,SAAS,CAAC,GAAG;AACjH;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE;AAC/E,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI;AACjC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG;AACrC,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE;AACpC,QAAQ,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AAC/D,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa;AACnD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC;AACxE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU;AAC9E,KAAK,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;AACvD,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE;AACrC,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU;AACnE,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD;AACA,QAAQ,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE;AAC7E,IAAI,CAAC;AACL,GAAG;AACH;AACA;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;ACxIpB,CAAC,QAAQ,GAAG,CAAC,CAAC;AACd;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,iBAAiB;AAC/B,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;AACrE,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;AACrD,KAAK,CAAC,CAAC,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,yBAAyB,CAAC,GAAG;AAC5F,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,aAAa;AAC5E,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;AACjI,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC;AACR,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,kBAAkB,EAAE;AACvC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,IAAI,CAAC;AACxB,KAAK,CAAC,MAAM,MAAM,CAAC,CAAC,IAAI,CAAC;AACzB,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;AAC3C,KAAK,CAAC,CAAC,CAAC;AACR,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC;AAClI,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC;AACzE,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG;AAC/F,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAClE,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,EAAE;AAC/G,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC;AAC3I,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS;AAC9F,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC;AACR,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,kBAAkB,EAAE;AACvC,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC;AAC9D,KAAK,CAAC,CAAC,CAAC;AACR;AACA,IAAI,CAAC;AACL,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC7B,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,UAAU;AACxC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AAC5D,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AAC7B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC/B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC/B,KAAK,EAAE;AACP,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAC7C,QAAQ,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC;AAC/B;AACA,QAAQ,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAChC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AAC7B,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM;AAC7B,QAAQ,EAAE;AACV,QAAQ,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;AAC/B,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AAC7B,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM;AAC7B,QAAQ,GAAG;AACX,QAAQ,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,QAAQ,GAAG;AAChG;AACA,QAAQ,KAAK,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC5H,YAAY,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACpE,YAAY,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACpE,YAAY,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE;AACrC,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACtC,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC;AACrC,YAAY,GAAG;AACf,YAAY,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,GAAG;AAC/G,QAAQ,CAAC;AACT,QAAQ,OAAO,CAAC,UAAU,CAAC,OAAO,GAAG;AACrC,QAAQ,OAAO,CAAC,QAAQ,CAAC,OAAO,GAAG;AACnC,QAAQ,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,QAAQ,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD;AACA,QAAQ,aAAa,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,GAAG;AACxD,IAAI,EAAE;AACN;AACA,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,iBAAiB,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;AAC7H;AACA,QAAQ,EAAE,OAAO;AACjB,QAAQ,YAAY,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AACzD,YAAY,MAAM,CAAC,CAAC;AACpB,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE;AAC/C,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC/C,YAAY,EAAE;AACd,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,OAAO;AACjB,QAAQ,4BAA4B,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,YAAY,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACxB,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG;AAC1B;AACA,YAAY,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC1E,YAAY,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC7C,gBAAgB,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE;AACxC,gBAAgB,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACvC,YAAY,CAAC;AACb,YAAY,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AACxC,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE;AACxC,YAAY,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClC,YAAY,MAAM,CAAC,GAAG,CAAC;AACvB,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE;AACnF,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AAC5B,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI;AACrC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG;AACzC,SAAS,EAAE;AACX,QAAQ,QAAQ,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACvC,YAAY,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE;AACpE,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa;AACvD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC;AAC5E,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU;AAClF,SAAS,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;AAC3D,SAAS,EAAE;AACX,QAAQ,SAAS,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACxC,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC5B,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC5B,SAAS,EAAE;AACX,QAAQ,UAAU,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3C,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE;AACjC,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,YAAY,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,4BAA4B,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACrE,YAAY,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE;AAC3C,YAAY,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE;AACnG;AACA,QAAQ,CAAC;AACT,IAAI,GAAG;AACP;AACA,EAAE,aAAa,GAAG;AAClB;;AC7IA,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB;AACnC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,gBAAgB;AAC1B,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,gBAAgB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM;AACzF,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY;AAChF,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;AAC/E,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM;AACjF,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI;AAC5E,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC;AACd,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,UAAU;AACpC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI;AAC9E,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI;AAC/E,CAAC,CAAC,MAAM,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC;AAC/E,CAAC,CAAC,MAAM,YAAY,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI;AACxE,CAAC,CAAC,MAAM,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC;AAC5B,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AACjC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU;AAChC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC9B,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AACjC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC9B,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC9B,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,MAAM;AAC5B,CAAC,EAAE;AACH,EAAE,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACzC;AACA,IAAI,GAAG,CAAC,OAAO,CAAC;AAChB,QAAQ,KAAK,CAAC;AACd,QAAQ,MAAM,CAAC;AACf;AACA,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AAC9B,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC;AACnB,YAAY,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE;AACzC,YAAY,MAAM,CAAC,CAAC,MAAM;AAC1B,QAAQ,EAAE;AACV,IAAI,CAAC;AACL;AACA,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO;AAC7D,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;AACnD;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtC,QAAQ,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;AAClE,QAAQ,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;AACpE,IAAI,CAAC;AACL,IAAI,IAAI,CAAC,CAAC;AACV,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAClB,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACnB,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE;AAC9D,IAAI,CAAC;AACL;AACA,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC9B,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC;AACrB,QAAQ,MAAM,CAAC,CAAC,MAAM,CAAC;AACvB,QAAQ,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE;AAC5C,QAAQ,WAAW,CAAC,CAAC,CAAC,CAAC;AACvB,QAAQ,QAAQ,CAAC,CAAC,CAAC,CAAC;AACpB,QAAQ,QAAQ,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3E,IAAI,CAAC,CAAC,EAAE;AACR;AACA,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AAC5C;AACA,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACjC,EAAE;AACF;AACA,EAAE,MAAM,CAAC,CAAC,EAAE,gBAAgB,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,SAAS,CAAC,GAAG;AACvH,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE;AAC/E,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI;AACjC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG;AACrC,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE;AACpC,QAAQ,MAAM,CAAC,CAAC;AAChB,YAAY,IAAI,CAAC,IAAI,CAAC,EAAE;AACxB,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI;AAC/C,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC;AACd,YAAY,IAAI,CAAC,eAAe,CAAC,EAAE;AACnC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,IAAI,EAAE;AAC/E,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa;AACxE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC;AAC5E,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU;AAC9E,KAAK,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;AACvD,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,EAAE;AAClD;AACA,QAAQ,GAAG,CAAC,OAAO,CAAC;AACpB;AACA,QAAQ,EAAE,CAAC,CAAC,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC,EAAE;AAC9C;AACA,YAAY,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,EAAE;AAC9D;AACA,QAAQ,CAAC,IAAI,CAAC;AACd;AACA,YAAY,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,EAAE;AACjE,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,OAAO,CAAC;AACvB;AACA,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACvC,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC;AAC7B,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC3F,YAAY,UAAU,CAAC,CAAC;AACxB,gBAAgB,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;AAC5C,gBAAgB,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC;AACnD,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,UAAU,CAAC;AAC1B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,EAAE;AACP,IAAI,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpC,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,EAAE;AAChD,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE;AACrB,YAAY,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACvC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACvC,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK;AAChF,KAAK,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI;AAC3E,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK;AACzE,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC;AAC/D,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;AACtB,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1C,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AACvB,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC3F,YAAY,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC;AAC3C,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,GAAG,CAAC;AACnB,IAAI,CAAC;AACL,CAAC,CAAC,EAAE;AACJ;AACA,GAAG;AACH,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,gBAAgB,CAAC;AAC5D,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,EAAE;AACH,QAAQ,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC9B,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG;AACtB,QAAQ,IAAI,CAAC;AACb,QAAQ,CAAC,CAAC;AACV,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;AACxC,QAAQ,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;AAC1B,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;AAC1B,YAAY,IAAI,CAAC,KAAK,CAAC,EAAE;AACzB,YAAY,IAAI,CAAC,GAAG,CAAC,EAAE;AACvB,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK;AACpD,YAAY,QAAQ,CAAC,IAAI,EAAE;AAC3B,gBAAgB,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AAC9B,gBAAgB,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AAC5C,gBAAgB,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC7C,YAAY,GAAG;AACf,QAAQ,CAAC;AACT,QAAQ,IAAI,CAAC,CAAC;AACd,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE;AAChG,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,QAAQ,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AACnC,IAAI,GAAG;AACP;AACA,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,EAAE;AACH,QAAQ,CAAC,gBAAgB,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,EAAE;AAChD;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAC/C,QAAQ,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;AACvD,IAAI,CAAC;AACL;AACA,IAAI,GAAG,CAAC,IAAI,SAAS,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC;AAC9C,QAAQ,QAAQ,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AACpC,QAAQ,IAAI,SAAS,CAAC,CAAC,IAAI,CAAC;AAC5B,QAAQ,MAAM,OAAO,CAAC,CAAC,GAAG;AAC1B,QAAQ,KAAK,CAAC;AACd,QAAQ,CAAC,CAAC;AACV;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAChC;AACA,QAAQ,GAAG,CAAC,CAAC;AACb,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,gBAAgB,IAAI,CAAC,QAAQ,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzD,gBAAgB,MAAM,CAAC,MAAM,EAAE;AAC/B,YAAY,EAAE;AACd;AACA,YAAY,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AAC1D,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACnD,gBAAgB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;AACpC;AACA,gBAAgB,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;AAClC,oBAAoB,GAAG,CAAC,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AACxD,oBAAoB,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAC1E,oBAAoB,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAC1E,gBAAgB,GAAG;AACnB,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,mBAAmB,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE;AAC3D;AACA,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvB,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;AACxC,gBAAgB,CAAC,CAAC,CAAC;AACnB,gBAAgB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE;AAC/E,QAAQ,CAAC;AACT,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,QAAQ,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,EAAE;AACjF,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,QAAQ,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;AAC9C,IAAI,CAAC;AACL;AACA,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE;AACrD,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,EAAE;AACH,QAAQ,CAAC,mBAAmB,CAAC,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC,EAAE;AAC1D;AACA,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC;AAChC;AACA,CAAC;AACD;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;ACjSpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,eAAe;AAClC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AACf;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe;AAC7B,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM;AACxE,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC;AACpC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC;AACnD,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG;AACpD,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC,MAAM,IAAI;AACxE,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,mBAAmB,CAAC,GAAG;AAC5E,KAAK,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG;AACtE,KAAK,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;AAChD,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,UAAU;AACxC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AACnD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AAC/E,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;AACzE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG;AACjF,KAAK,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI;AAC/E,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK;AAC9E,KAAK,CAAC,CAAC,OAAO,CAAC;AACf,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG;AACjF,KAAK,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE;AAClF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG;AAChF,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC;AACzB,KAAK,EAAE;AACP,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC5C;AACA,QAAQ,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE;AAC5B,YAAY,YAAY,CAAC,CAAC,IAAI,CAAC;AAC/B,YAAY,iBAAiB,CAAC,CAAC,KAAK,CAAC;AACrC,YAAY,mBAAmB,CAAC,CAAC,KAAK,CAAC;AACvC,YAAY,SAAS,CAAC,CAAC,IAAI;AAC3B,QAAQ,EAAE,CAAC,OAAO,EAAE;AACpB,QAAQ,EAAE,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,GAAG;AAC5C;AACA,IAAI,EAAE;AACN;AACA,IAAI,EAAE,MAAM,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,eAAe,CAAC,SAAS,CAAC,GAAG;AACxH,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE;AACnF,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AAC5B,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI;AACrC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG;AACzC,SAAS,EAAE;AACX,QAAQ,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACxC,YAAY,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AACtD,QAAQ,EAAE;AACV,QAAQ,GAAG;AACX,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO;AAChD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC;AAClF,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU;AAClF,SAAS,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;AAC3D,SAAS,EAAE;AACX,QAAQ,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAChD,YAAY,MAAM,CAAC,OAAO,CAAC;AAC3B,QAAQ,EAAE;AACV,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACtD,SAAS,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC;AACvE,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG;AAC9B,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;AAC1B,SAAS,EAAE;AACX,QAAQ,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACtC,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG;AAClD,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7B;AACA,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;AACzC,gBAAgB,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC;AAC3D,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;AAC3C,gBAAgB,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC;AAChE,YAAY,CAAC;AACb;AACA,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACnD,gBAAgB,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE;AAC5E,gBAAgB,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC7H,gBAAgB,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;AACjI,gBAAgB,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;AAC/D,gBAAgB,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE;AAC1E,gBAAgB,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC/C,gBAAgB,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;AACjD,gBAAgB,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AACtC,gBAAgB,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,gBAAgB,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,GAAG;AACpD,gBAAgB,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACzD;AACA,gBAAgB,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACnC;AACA,gBAAgB,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,UAAU;AAC1E,gBAAgB,KAAK,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,GAAG;AAC/D,YAAY,GAAG;AACf;AACA,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACpD,gBAAgB,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,UAAU;AAC1E,gBAAgB,KAAK,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AACjD,oBAAoB,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAC7D,oBAAoB,MAAM,CAAC,CAAC,GAAG;AAC/B,gBAAgB,GAAG;AACnB,YAAY,GAAG;AACf;AACA,YAAY,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AAC5B,QAAQ,EAAE;AACV,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,EAAE;AACX,QAAQ,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACzC,YAAY,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC;AACjC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AACnE,gBAAgB,UAAU,CAAC,CAAC;AAC5B,wBAAwB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAClD,wBAAwB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC;AACzD,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,UAAU,CAAC;AAC9B,QAAQ,EAAE;AACV,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAChC,SAAS,EAAE;AACX,QAAQ,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACvC,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE;AAClD,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACxB,gBAAgB,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACzC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACzC,YAAY,CAAC;AACb,QAAQ,EAAE;AACV,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG;AAC/B,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI;AAClD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI;AACrD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI;AACrD,SAAS,EAAE;AACX,QAAQ,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,YAAY,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3B,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AACnE,gBAAgB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC;AAC7C,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,GAAG,CAAC;AACvB,QAAQ,EAAE;AACV,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AACtC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI;AAClD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI;AACrD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI;AACrD,SAAS,EAAE;AACX,QAAQ,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,YAAY,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AACnE,gBAAgB,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC;AACvD,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,OAAO,CAAC;AAC3B,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,OAAO;AAClB,QAAQ,EAAE;AACV,QAAQ,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ;AAClE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE;AACrE,QAAQ,YAAY,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACnC,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AAC3B,oBAAoB,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;AACzC,oBAAoB,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE;AAChF,oBAAoB,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;AAC5I,oBAAoB,MAAM,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM;AAChJ,gBAAgB,GAAG;AACnB;AACA,YAAY,EAAE,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AAC7E,gBAAgB,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;AACvE,gBAAgB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AACnC,gBAAgB,MAAM,CAAC,MAAM,CAAC;AAC9B,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE;AACxE,YAAY,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;AAChJ,YAAY,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;AACpJ;AACA;AACA,YAAY,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG;AAC7D,YAAY,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,GAAG;AACxD;AACA,YAAY,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC;AAC3C,YAAY,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC;AAC7C,YAAY,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,aAAa,EAAE;AACjF,YAAY,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO;AAC5E,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG;AACvE,YAAY,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC;AAClC,YAAY,MAAM,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC;AAC7C,YAAY,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;AACnE,YAAY,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/B;AACA,YAAY,EAAE,CAAC,GAAG,eAAe,CAAC,SAAS,EAAE,CAAC,CAAC;AAC/C,gBAAgB,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;AAC1E,gBAAgB,MAAM,CAAC,MAAM,CAAC;AAC9B,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO;AAC3E,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;AAC5B,YAAY,KAAK,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,gBAAgB,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE;AAC5D,gBAAgB,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9D,gBAAgB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG;AACnE,gBAAgB,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,UAAU,EAAE,EAAE,GAAG;AAChE,gBAAgB,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC;AACjD,gBAAgB,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC;AACnD,gBAAgB,YAAY,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,aAAa,EAAE;AACrF;AACA,gBAAgB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,oBAAoB,SAAS,CAAC,CAAC,YAAY,CAAC;AAC5C,oBAAoB,KAAK,CAAC,CAAC,YAAY,CAAC;AACxC,oBAAoB,MAAM,CAAC,CAAC,aAAa;AACzC,gBAAgB,GAAG;AACnB;AACA,gBAAgB,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC;AACxC,gBAAgB,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC;AAC1C,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,MAAM,CAAC;AAC1B,QAAQ,CAAC;AACT,IAAI,GAAG;AACP;AACA,EAAE,aAAa,GAAG;;ACvQlB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,oBAAoB;AACvC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,GAAG,CAAC,CAAC;AACd;AACA,EAAE,CAAC,UAAU;AACb,EAAE,oBAAoB,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACxE,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE,oBAAoB,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,GAAG;AAC7E,EAAE;AACF;AACA,EAAE,aAAa,GAAG;;ACzClB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM;AACzB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,GAAG;AACH,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM;AAClC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACjB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI;AAC1B,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC3B,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC3B,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI;AAC1B,CAAC,EAAE;AACH,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;AACjB,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC;AACd,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC;AACd,IAAI,IAAI,CAAC,GAAG,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI;AACrF,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI;AACvE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC;AAC1B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,WAAW;AACrC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAC1B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC;AAClI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG;AACvF,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;AACxB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;AAC9E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC;AAC7E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC;AAChF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;AAC9E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;AACxE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;AACxF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE;AAClI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE;AACtI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE;AAClI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE;AAClI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE;AAChI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE;AAClI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE;AAChI,CAAC,EAAE;AACH,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAChC;AACA,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACrB;AACA,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/B;AACA,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3B;AACA,QAAQ,OAAO,CAAC,YAAY,IAAI,CAAC;AACjC,QAAQ,OAAO,CAAC,YAAY,IAAI,CAAC;AACjC,QAAQ,QAAQ,CAAC,WAAW,IAAI,CAAC;AACjC,QAAQ,QAAQ,CAAC,WAAW,IAAI,CAAC;AACjC,QAAQ,OAAO,CAAC,YAAY,IAAI,CAAC;AACjC,QAAQ,kBAAkB,CAAC,CAAC,EAAE,gBAAgB,CAAC,kBAAkB,CAAC;AAClE,QAAQ,kBAAkB,CAAC,CAAC,EAAE,gBAAgB,CAAC,kBAAkB,CAAC;AAClE,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS;AACrC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AAC1C,SAAS,EAAE;AACX,QAAQ,SAAS,CAAC,UAAU,CAAC,CAAC;AAC9B,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;AACtD,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU;AACtC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AAC1C,SAAS,EAAE;AACX,QAAQ,UAAU,CAAC,SAAS,IAAI,CAAC;AACjC,QAAQ,OAAO,CAAC,YAAY,IAAI,CAAC;AACjC,QAAQ,SAAS,CAAC,UAAU,IAAI,CAAC;AACjC,QAAQ,OAAO,CAAC,YAAY,IAAI,CAAC;AACjC,QAAQ,OAAO,CAAC,YAAY,IAAI,CAAC;AACjC,QAAQ,MAAM,CAAC,aAAa,IAAI,CAAC;AACjC,QAAQ,OAAO,CAAC,YAAY,IAAI,CAAC;AACjC,QAAQ,MAAM,CAAC,aAAa,IAAI;AAChC;AACA,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE;AACjB;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;AAC1B,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AAChC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AACtC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,kBAAkB,EAAE,GAAG,GAAG;AAClE;AACA,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU;AAC7E,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM;AAChD,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC7B,QAAQ,IAAI,CAAC,OAAO,MAAM,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AACnE,QAAQ,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AACpE,QAAQ,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AACpE,QAAQ,IAAI,CAAC,OAAO,MAAM,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AACnE;AACA,QAAQ,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;AAC3B,QAAQ,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAC3B,QAAQ,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAC3B,QAAQ,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;AAC3B,YAAY,IAAI,CAAC,OAAO,CAAC;AACzB;AACA,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;AACjD,QAAQ,EAAE,yBAAyB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AACpD;AACA,QAAQ,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;AACtC,QAAQ,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;AACtC,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;AACtC,YAAY,CAAC,QAAQ,EAAE;AACvB;AACA,QAAQ,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACjC,QAAQ,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACjC,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;AACjC,YAAY,CAAC,GAAG,EAAE;AAClB;AACA,QAAQ,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAClC,QAAQ,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAClC,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;AAClC,YAAY,CAAC,GAAG,EAAE;AAClB;AACA,QAAQ,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;AACxC,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;AACxC,YAAY,CAAC,MAAM,EAAE;AACrB;AACA,QAAQ,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9E,YAAY,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACrC,YAAY,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACrC,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;AACrC,gBAAgB,GAAG;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AACjD,QAAQ,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AAClD,QAAQ,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AAClD,QAAQ,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AACjD,IAAI,CAAC;AACL;AACA;AACA,IAAI,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE;AAC3C,IAAI,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE;AAC/C,IAAI,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE;AAC3C,IAAI,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE;AAC3C,IAAI,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE;AACzC,IAAI,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE;AAC3C,IAAI,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE;AACzC;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AAClC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,YAAY;AACvD,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AACtC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC;AAC5C;AACA,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC;AAC1C,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC;AAC/B,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;AACtF,IAAI,IAAI,CAAC,UAAU,KAAK,CAAC,CAAC,KAAK,CAAC;AAChC;AACA,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE;AACjD,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;AAC7C,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,UAAU,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AAC/C;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AACnD,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO;AACnD,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AACtC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,YAAY,EAAE;AACvC;AACA,QAAQ,OAAO,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC;AACzC,QAAQ,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AACpD,QAAQ,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AACpD;AACA,QAAQ,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACzC,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;AAC/C,gBAAgB,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE;AAClD,gBAAgB,GAAG;AACnB,iBAAiB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;AACpE,iBAAiB,CAAC;AAClB,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK;AAC/B,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACjD,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACjC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACnH,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7E,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AACtF,iBAAiB,EAAE;AACnB,gBAAgB,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE;AACpF,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AAChD,gBAAgB,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE;AACnD,YAAY,CAAC;AACb,QAAQ,EAAE;AACV;AACA,QAAQ,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC1C,YAAY,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,EAAE;AACvC,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;AAC7D,aAAa,CAAC;AACd,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK;AAC3B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AAC7C,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC/G,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACzE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,aAAa,EAAE;AACf,YAAY,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE;AAChF,QAAQ,EAAE;AACV;AACA,QAAQ,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxC,YAAY,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE;AAChD,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;AAC/C,gBAAgB,GAAG;AACnB,iBAAiB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;AACpE,iBAAiB,CAAC;AAClB,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;AAC9B,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACjD,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACjC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACnH,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7E,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AACtF,iBAAiB,EAAE;AACnB,gBAAgB,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE;AACnF,YAAY,CAAC;AACb,QAAQ,EAAE;AACV;AACA,QAAQ,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACzC,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACtC,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;AAC1D,aAAa,CAAC;AACd,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;AAC1B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AAC7C,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC/G,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACzE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,aAAa,EAAE;AACf,YAAY,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE;AAC/E,QAAQ,EAAE;AACV;AACA,QAAQ,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC1C,YAAY,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE;AAC9C,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;AAC3F,aAAa,CAAC;AACd,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK;AAC3B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AAC7C,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC/G,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACzE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,aAAa,EAAE;AACf,YAAY,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE;AAChF,QAAQ,EAAE;AACV;AACA,QAAQ,cAAc,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3C,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;AAC9E,gBAAgB,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE;AACpD,gBAAgB,GAAG;AACnB,iBAAiB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;AAChG,iBAAiB,CAAC;AAClB,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO;AACjC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACjD,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACjC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACnH,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7E,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AACtF,iBAAiB,EAAE;AACnB,gBAAgB,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE;AACtF,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;AACtD,gBAAgB,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE;AACpD,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE;AACnD,YAAY,CAAC;AACb,QAAQ,EAAE;AACV;AACA,QAAQ,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACzC,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChC,gBAAgB,GAAG;AACnB,iBAAiB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC;AACnK,iBAAiB,CAAC;AAClB,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK;AAC/B,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACjD,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACjC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACnH,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7E,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AACtF,iBAAiB,EAAE;AACnB,gBAAgB,KAAK,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG;AAClF,YAAY,CAAC;AACb,QAAQ,EAAE;AACV;AACA,QAAQ,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACtC,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE;AAClF,YAAY,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;AACvC,gBAAgB,IAAI;AACpB,iBAAiB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC;AACnK,iBAAiB,CAAC;AAClB,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK;AAC/B,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACjD,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACjC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACnH,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7E,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AACtF,iBAAiB,EAAE;AACnB,gBAAgB,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE;AACpF,gBAAgB,IAAI;AACpB,iBAAiB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;AAChG,iBAAiB,CAAC;AAClB,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO;AACjC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACjD,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACjC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACnH,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7E,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AACtF,iBAAiB,EAAE;AACnB,gBAAgB,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE;AACtF,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT;AACA,IAAI,GAAG;AACP;AACA,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE;AACtC,EAAE;AACF;AACA,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG;AACpG;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ;AAChF,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AAC9B,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,EAAE;AACP,IAAI,gBAAgB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAClC,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE;AAC1C,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ;AAChF,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AAC9B,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,EAAE;AACP,IAAI,eAAe,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACjC,QAAQ,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE;AAC1C,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,EAAE;AACP,IAAI,OAAO,CAAC,CAAC,QAAQ,GAAG;AACxB,QAAQ,IAAI,CAAC,eAAe,GAAG;AAC/B,QAAQ,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,QAAQ,EAAE,iBAAiB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;AACvD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,GAAG;AACvB,QAAQ,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AACtC,QAAQ,EAAE,iBAAiB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;AACvD,QAAQ,IAAI,CAAC,gBAAgB,GAAG;AAChC,IAAI,CAAC;AACL;AACA,GAAG;AACH;AACA;AACA,QAAQ,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACjC,IAAI,EAAE,qBAAqB,CAAC,QAAQ,GAAG;AACvC,QAAQ,UAAU,CAAC,CAAC,MAAM,CAAC,EAAE;AAC7B,IAAI,GAAG;AACP,CAAC;AACD;AACA,QAAQ,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC/B,IAAI,GAAG,CAAC,WAAW,CAAC;AACpB,QAAQ,SAAS,CAAC;AAClB,QAAQ,OAAO,CAAC;AAChB;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC9B,QAAQ,WAAW,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AAC9B,QAAQ,SAAS,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC;AACzD,QAAQ,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;AAC1D,QAAQ,OAAO,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE;AAC/C,QAAQ,OAAO,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE;AAC/C;AACA,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;AAC9B,YAAY,EAAE,iBAAiB,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE;AAClE,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,YAAY,EAAE,CAAC,IAAI,CAAC,KAAK;AACzB,YAAY,YAAY,CAAC,CAAC,MAAM,CAAC,EAAE;AACnC,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,CAAC;AACD;AACA,QAAQ,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAChC,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7B,IAAI,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC;AACtD,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC,QAAQ,GAAG;AAClC,QAAQ,YAAY,CAAC,CAAC,MAAM,CAAC,EAAE;AAC/B,IAAI,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE;AAC1B,CAAC;AACD;AACA,QAAQ,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC/B,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC;AAC9B,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;AAC1B,QAAQ,EAAE,iBAAiB,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;AAC1D,IAAI,CAAC;AACL,CAAC;AACD;AACA,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACnC;AACA,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;AAClC,QAAQ,MAAM,CAAC;AACf,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE;AAC3C,SAAS,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACtD,QAAQ,UAAU,CAAC,CAAC,MAAM,CAAC,EAAE;AAC7B,QAAQ,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC;AAClD,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE;AAC3C,SAAS,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACvD,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;AAC9B,YAAY,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG;AAClD,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC;AAClD,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE;AAC1C,SAAS,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACvD,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;AAC7B,YAAY,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG;AACjD,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,IAAI,CAAC;AACjD,IAAI,CAAC;AACL,CAAC;AACD;AACA;AACA,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACpC;AACA,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;AAClC,QAAQ,MAAM,CAAC;AACf,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE;AAC3C,SAAS,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACtD,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;AAC7B,YAAY,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE;AACvD,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC;AAClD,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE;AAC3C,SAAS,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACvD,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;AAC9B,YAAY,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE;AACxD,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC;AAClD,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE;AAC1C,SAAS,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACvD,QAAQ,WAAW,CAAC,CAAC,MAAM,CAAC,EAAE;AAC9B,QAAQ,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,IAAI,CAAC;AACjD,IAAI,CAAC;AACL,CAAC;AACD;AACA;AACA;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;AC3fpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW;AAC9B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW;AACrB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC;AAClD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC;AAClG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO;AAClD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS;AACrE,CAAC,GAAG;AACJ,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACrC;AACA,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3B,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC;AACtD,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO;AAClC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,WAAW,CAAC;AAC/C,SAAS,EAAE;AACX,QAAQ,OAAO,CAAC,YAAY,GAAG;AAC/B,QAAQ,kBAAkB,CAAC,CAAC,EAAE,gBAAgB,CAAC,kBAAkB,CAAC;AAClE,QAAQ,kBAAkB,CAAC,CAAC,EAAE,gBAAgB,CAAC,kBAAkB,CAAC;AAClE,QAAQ,SAAS,CAAC,UAAU,EAAE;AAC9B,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE;AACjB;AACA,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC;AAC3C,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK;AAC1C,QAAQ,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACrB,QAAQ,CAAC,CAAC;AACV;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;AAC5C,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AAChC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,WAAW,CAAC;AAC3C,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AACpE;AACA,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC;AACxD,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AACzB,QAAQ,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AACvD,QAAQ,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY;AAC/C,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AAChD,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE;AACpD,QAAQ,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AAC/C,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAChD,YAAY,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE;AAC7D,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,EAAE,yBAAyB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AAChD;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC;AAClE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO;AACnD,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,WAAW,CAAC;AAC3C,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,YAAY,EAAE;AACvC,QAAQ,OAAO,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC;AACzC,QAAQ,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AACpD,QAAQ,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AACpD,QAAQ,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC1C,YAAY,GAAG,CAAC,CAAC,CAAC;AAClB,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC1D,gBAAgB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,gBAAgB,GAAG;AACtD,YAAY,CAAC;AACb,QAAQ,EAAE;AACV,QAAQ,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACzC,YAAY,GAAG,CAAC,CAAC,CAAC;AAClB,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;AAChD,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9D,oBAAoB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,eAAe,GAAG;AACzD,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,EAAE;AACV,IAAI,GAAG;AACP,EAAE;AACF;AACA,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE;AACjD,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC3B;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM;AAC/E,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC;AAC1B,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,EAAE;AACP,IAAI,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC9B,QAAQ,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AACnE,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM;AAC/E,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC;AAC1B,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,EAAE;AACP,IAAI,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC7B,QAAQ,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AAClE,IAAI,CAAC;AACL,EAAE;AACF;AACA;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;ACvIpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI;AACvB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,GAAG,CAAC,CAAC;AACd;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;AACd,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;AAChF,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAChD,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AAC7E,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AACtC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AACvC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AAC5E,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;AAClD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;AAClD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE;AAC1D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE;AAC5D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC;AACjF,CAAC,EAAE;AACH,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACjD,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;AAChC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACzB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;AAChC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACzB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE;AACpC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC7B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACzD,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE;AACrC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AAC9B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3D;AACA,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D;AACA,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC;AAChC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE;AACvD,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC;AAC7B,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;AAC9B,QAAQ,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG;AACxC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;AAC9B,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;AAC9B,QAAQ,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/B,QAAQ,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;AACjC,QAAQ,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC9B,QAAQ,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC;AAC5B,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;AACrC,QAAQ,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG;AAC3C,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;AAC9B,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;AAC9B,QAAQ,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC;AAC5B,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACpC,QAAQ,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,GAAG;AAC1C,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;AAC9B,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;AAC9B,QAAQ,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/B,QAAQ,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;AACjC,QAAQ,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC9B,QAAQ,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;AAC3B,IAAI,CAAC;AACL,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC;AAC/D,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI;AAC/B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,OAAO;AACvC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ;AACxC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,UAAU;AAC1C,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC;AAChC,CAAC,EAAE;AACH,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;AAC9D,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,EAAE;AAC7C,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,EAAE;AAChD,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE;AACvC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AAC7C,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrB,QAAQ,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;AAC3B,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,QAAQ,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;AAC/B,IAAI,CAAC;AACL,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AACtB,QAAQ,OAAO,CAAC,CAAC,CAAC;AAClB,QAAQ,OAAO,CAAC,CAAC,CAAC;AAClB,QAAQ,KAAK,CAAC;AACd,QAAQ,MAAM,CAAC;AACf,QAAQ,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;AACjC,EAAE;AACF;AACA,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;AAC1C,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACpB,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI;AAC7D,KAAK,EAAE;AACP,IAAI,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACvB,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC1B,YAAY,IAAI,CAAC,CAAC,CAAC;AACnB,YAAY,IAAI,CAAC,CAAC,CAAC;AACnB,YAAY,IAAI,CAAC,KAAK,CAAC;AACvB,YAAY,IAAI,CAAC,MAAM,CAAC;AACxB,YAAY,IAAI,CAAC,OAAO,EAAE;AAC1B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC;AAC/D,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC;AACtD,KAAK,EAAE;AACP,IAAI,cAAc,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAChC,QAAQ,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;AACxC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;AAC9E,KAAK,CAAC,CAAC,KAAK,CAAC;AACb,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;AAChF,KAAK,CAAC,EAAE,GAAG,CAAC,SAAS,CAAC;AACtB,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC5B,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AAC3B,YAAY,IAAI,CAAC,CAAC,CAAC;AACnB,YAAY,IAAI,CAAC,CAAC;AAClB,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;AAChF,KAAK,CAAC,CAAC,KAAK,CAAC;AACb,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;AAClF,KAAK,CAAC,EAAE,GAAG,CAAC,SAAS,CAAC;AACtB,KAAK,EAAE;AACP,IAAI,cAAc,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAChC,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;AACrE,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI;AACrD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;AAC7E,KAAK,CAAC,CAAC,KAAK,CAAC;AACb,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;AAC/E,KAAK,CAAC,EAAE,GAAG,CAAC,SAAS,CAAC;AACtB,KAAK,EAAE;AACP,IAAI,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC7B,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACvD,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI;AACrD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;AAC/E,KAAK,CAAC,CAAC,KAAK,CAAC;AACb,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;AACjF,KAAK,CAAC,EAAE,GAAG,CAAC,SAAS,CAAC;AACtB,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC/B,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;AACxD,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI;AACrD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;AAC5C,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,WAAW;AAChF,KAAK,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtD,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC3B,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AAC3B,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtC,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI;AAClD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK;AAC7E,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG;AAC/E,KAAK,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;AAC9C,KAAK,EAAE;AACP,IAAI,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACzB,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE;AACpD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;AAC/D,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;AACzE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE;AAC/E,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAC7B,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE;AAC3C,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AACjC,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AACjC,YAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;AACzC,YAAY,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;AAC3C,YAAY,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;AAC3C,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG;AAC3E,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;AACxB,IAAI,CAAC,CAAC,CAAC,QAAQ;AACf,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC;AACtE,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc;AAC9E,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AAC7C,IAAI,EAAE;AACN,IAAI,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AAC7B,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC1B,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AAC5B,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AAC5B,YAAY,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AAChC,YAAY,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;AACjC,YAAY,IAAI,CAAC,OAAO,EAAE;AAC1B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,IAAI,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;AAC/D,IAAI,CAAC,CAAC,CAAC,QAAQ;AACf,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC;AAChE,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ;AACpE,IAAI,EAAE;AACN,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAChC,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC1B,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC7B,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC7B,YAAY,IAAI,CAAC,KAAK,CAAC;AACvB,YAAY,IAAI,CAAC,MAAM,CAAC;AACxB,YAAY,IAAI,CAAC,OAAO,EAAE;AAC1B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK;AAC1E,KAAK,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;AAChC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI;AACvC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC;AACtD,KAAK,EAAE;AACP,IAAI,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3B,QAAQ,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG;AACpD,QAAQ,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG;AACrD;AACA,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,EAAE;AACnE,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,EAAE;AAClE,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AAC7B,YAAY,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC;AACtD,YAAY,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,EAAE;AACzD,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AAC9B,YAAY,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC;AACvD,YAAY,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,MAAM,EAAE;AAC1D;AACA,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC1B,YAAY,IAAI,CAAC;AACjB,YAAY,GAAG,CAAC;AAChB,YAAY,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,YAAY,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE;AAC1B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG;AAC9E,KAAK,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AACvB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI;AACvC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY;AACxE,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AACjD,KAAK,EAAE;AACP,IAAI,YAAY,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAClC,QAAQ,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS;AACnE,QAAQ,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,6BAA6B;AACnF,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC;AACrE,QAAQ,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;AACnD,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI;AAC3D,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI;AAC3D,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI;AACpD,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;AACnC;AACA,QAAQ,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,GAAG;AACpC;AACA,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,GAAG;AAC5C,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AACvD,YAAY,kBAAkB,CAAC,IAAI,CAAC,WAAW,EAAE;AACjD,QAAQ,CAAC;AACT,QAAQ,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG;AAC9C,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AACxD,YAAY,kBAAkB,CAAC,IAAI,CAAC,YAAY,EAAE;AAClD,QAAQ,CAAC;AACT,QAAQ,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,GAAG;AAClD,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AAC1D,YAAY,kBAAkB,CAAC,IAAI,CAAC,cAAc,EAAE;AACpD,QAAQ,CAAC;AACT,QAAQ,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG;AACpD,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AAC3D,YAAY,kBAAkB,CAAC,IAAI,CAAC,eAAe,EAAE;AACrD,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,GAAG;AAC5C,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AACvD,YAAY,kBAAkB,CAAC,IAAI,CAAC,WAAW,EAAE;AACjD,QAAQ,CAAC;AACT,QAAQ,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG;AAC9C,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AACxD,YAAY,kBAAkB,CAAC,IAAI,CAAC,YAAY,EAAE;AAClD,QAAQ,CAAC;AACT,QAAQ,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,GAAG;AAClD,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AAC1D,YAAY,kBAAkB,CAAC,IAAI,CAAC,cAAc,EAAE;AACpD,QAAQ,CAAC;AACT,QAAQ,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG;AACpD,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AAC3D,YAAY,kBAAkB,CAAC,IAAI,CAAC,eAAe,EAAE;AACrD,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,GAAG;AAC/C,QAAQ,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,GAAG;AAC/C,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACvD,YAAY,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE;AAC9C,YAAY,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC3D,gBAAgB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE;AAClD,gBAAgB,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE;AAC/E,oBAAoB,WAAW,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,GAAG;AACpD,gBAAgB,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAChC,oBAAoB,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE;AACvD,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,QAAQ,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,YAAY,EAAE,CAAC,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO;AACzD,YAAY,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AACtC,YAAY,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AACtC;AACA,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC3E,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,gBAAgB,MAAM,CAAC,IAAI,CAAC;AAC5B,YAAY,CAAC;AACb;AACA,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AAClF,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AAClF;AACA,YAAY,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE;AACpD,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACpD,gBAAgB,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE;AAC/E,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,kBAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC;AAC3C,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC;AAC3C,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC;AAC3C,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC;AAC3C,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC7D,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,EAAE;AAC9C,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACjC,gBAAgB,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/B,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACjC,gBAAgB,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/B,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACjC,gBAAgB,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/B,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACjC,gBAAgB,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/B,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE;AAChE,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC9B,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,GAAG;AACxC,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG;AAC1C,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,GAAG;AAC9C,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG;AAChD,QAAQ,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,QAAQ,EAAE;AACpC,YAAY,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE;AACpC,YAAY,CAAC,WAAW,CAAC,CAAC,UAAU,EAAE;AACtC,YAAY,CAAC,UAAU,CAAC,CAAC,OAAO,GAAG;AACnC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;AAC1C,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC;AAC9D,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC;AAC5E,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;AAC/C,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC;AACnC,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACtC,QAAQ,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE;AACjD,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,YAAY,MAAM,CAAC,IAAI,CAAC,KAAK,GAAG;AAChC,QAAQ,CAAC;AACT;AACA,QAAQ,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,GAAG;AAC1C,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE;AAClE,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE;AACpE;AACA,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,EAAE;AACjD,QAAQ,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK;AACtC,QAAQ,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,YAAY,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAChC,YAAY,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,QAAQ,GAAG;AACX,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACjD,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzB,YAAY,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;AAC/B,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChC,YAAY,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;AACnC,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC1B,YAAY,UAAU,CAAC,CAAC,CAAC;AACzB,YAAY,UAAU,CAAC,CAAC,CAAC;AACzB,YAAY,IAAI,CAAC,KAAK,CAAC;AACvB,YAAY,IAAI,CAAC,MAAM,CAAC;AACxB,YAAY,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;AACrC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ;AAC7E,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AACtB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,cAAc,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAChC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACjC,YAAY,MAAM,CAAC,IAAI,CAAC,KAAK,GAAG;AAChC,QAAQ,CAAC;AACT,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,GAAG;AACxC,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG;AAC1C,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,GAAG;AAC9C,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG;AAChD,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE;AAChF,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE;AAChF,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE;AAChF,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE;AAChF,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC1B,YAAY,IAAI,CAAC;AACjB,YAAY,IAAI,CAAC;AACjB,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACxB,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE;AACzB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ;AAC7E,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM;AAC7D,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,qBAAqB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACvC,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG;AAChD,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE;AAC1C,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE;AAC1C,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACrE,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACvE,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE;AAC/C,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE;AAC3E,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO;AAC9D,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK;AAC3E,KAAK,CAAC,CAAC,SAAS,CAAC;AACjB,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC7C,QAAQ,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AAC/B;AACA,QAAQ,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW;AACzE,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,GAAG;AACxC,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG;AAC1C,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,GAAG;AAC9C,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE;AAC9C,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE;AACjD;AACA,QAAQ,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACnD,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE;AAC7D;AACA,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACjD,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE;AAC7D;AACA,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACjD,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE;AAC9D;AACA,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACpD,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE;AAC9D,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG;AAC5E,KAAK,CAAC,CAAC,SAAS,CAAC;AACjB,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;AAClE,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC1B,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC;AACpB,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACrD,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACrD,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC1D,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5D,YAAY,IAAI;AAChB,IAAI,CAAC;AACL,EAAE;AACF;AACA;AACA,EAAE,aAAa,GAAG;;AC7iBlB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,cAAc;AACjC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjB;AACA,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU;AAC3C,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG;AACd;AACA,GAAG;AACH,CAAC,CAAC,EAAE,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI;AACrE,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU;AAClE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AACpE,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG;AACrE,CAAC,CAAC,EAAE,MAAM,CAAC;AACX,CAAC,CAAC;AACF,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW;AAC9D,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO;AACtE,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,WAAW;AAC/D,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AACpE,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC;AACtC,CAAC,CAAC;AACF,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO;AAC7E,CAAC,CAAC,UAAU,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,OAAO;AAC5E,CAAC,CAAC,UAAU,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,GAAG;AAC5E,CAAC,CAAC,UAAU,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW;AAC9E,CAAC,CAAC,UAAU,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC;AAClC,CAAC,EAAE;AACH,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc;AACxB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAC1B,CAAC,EAAE;AACH,EAAE,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACzC;AACA,IAAI,GAAG,CAAC,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC;AAC3B,QAAQ,MAAM,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACrC,QAAQ,UAAU,EAAE,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;AACzD,QAAQ,OAAO,CAAC;AAChB,QAAQ,KAAK,CAAC;AACd,QAAQ,CAAC,CAAC;AACV;AACA,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG;AAChE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO;AAC7C,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACxB,QAAQ,OAAO,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AAC9D,QAAQ,IAAI,CAAC,OAAO,YAAY,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAChE,QAAQ,IAAI,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;AAC7C,QAAQ,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,cAAc,EAAE;AACnD,IAAI,CAAC;AACL;AACA,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/B,QAAQ,SAAS,CAAC,EAAE,EAAE,gBAAgB,CAAC,uBAAuB,CAAC;AAC/D,QAAQ,QAAQ,CAAC,GAAG,EAAE,gBAAgB,CAAC,sBAAsB,CAAC;AAC9D,QAAQ,MAAM,CAAC,KAAK,EAAE,gBAAgB,CAAC,oBAAoB,CAAC;AAC5D,QAAQ,kBAAkB,CAAC,EAAE,EAAE,gBAAgB,CAAC,kBAAkB;AAClE,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;AACjB,QAAQ,EAAE,QAAQ,CAAC,SAAS;AAC5B,QAAQ,OAAO,CAAC,gBAAgB,IAAI,CAAC,OAAO,CAAC;AAC7C,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK;AAChE,QAAQ,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;AAChE,QAAQ,aAAa,CAAC,UAAU,KAAK,CAAC;AACtC,QAAQ,eAAe,CAAC,QAAQ,KAAK,CAAC;AACtC,QAAQ,qBAAqB,CAAC,EAAE,KAAK,CAAC;AACtC,QAAQ,mBAAmB,CAAC,IAAI,KAAK;AACrC,IAAI,CAAC,CAAC,EAAE;AACR;AACA,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE;AAC9B,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,UAAU;AAC9B,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACrB,QAAQ,CAAC,SAAS,EAAE,WAAW,KAAK;AACpC,IAAI,EAAE;AACN;AACA,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;AACnD;AACA,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;AAC/B,IAAI,KAAK,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE;AAChC,IAAI,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE;AAChC,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;AAChC,IAAI,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE;AAChC,IAAI,KAAK,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG,EAAE;AAChC,IAAI,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE;AAChC,IAAI,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE;AAChC,IAAI,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE;AACjC,IAAI,KAAK,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE;AACrC;AACA,IAAI,EAAE,yBAAyB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AAChD;AACA,IAAI,EAAE,iBAAiB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC7C;AACA,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;AACzB,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;AAC7C,QAAQ,OAAO,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC;AACrC,QAAQ,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,EAAE;AACxD,QAAQ,aAAa,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,EAAE;AAC1D,QAAQ,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,EAAE;AACzD,QAAQ,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,EAAE;AACxD,QAAQ,cAAc,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,EAAE;AACtD,QAAQ,UAAU,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC;AACtD,IAAI,CAAC,CAAC,EAAE;AACR;AACA,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG;AAC/E,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM;AAClC,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5C,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACzD,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAC1D,QAAQ,MAAM,CAAC,UAAU,CAAC;AAC1B,YAAY,IAAI,CAAC,OAAO,CAAC;AACzB,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;AACnD,QAAQ,EAAE;AACV,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC/C,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxC,gBAAgB,UAAU,CAAC,CAAC,CAAC,CAAC;AAC9B,gBAAgB,OAAO,CAAC,SAAS,CAAC,CAAC;AACnC,gBAAgB,MAAM,CAAC,WAAW,CAAC,MAAM;AACzC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAC1D;AACA,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACzC,gBAAgB,UAAU,CAAC,CAAC,CAAC,CAAC;AAC9B,gBAAgB,OAAO,CAAC,SAAS;AACjC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACrB;AACA,YAAY,MAAM,CAAC,UAAU,CAAC;AAC9B,gBAAgB,IAAI,CAAC,OAAO,CAAC;AAC7B,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;AACvD,YAAY,EAAE;AACd,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACzC,gBAAgB,UAAU,CAAC,CAAC,CAAC,CAAC;AAC9B,gBAAgB,OAAO,CAAC,SAAS,CAAC,CAAC;AACnC,gBAAgB,MAAM,CAAC,WAAW,CAAC,MAAM;AACzC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAC1D;AACA,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxC,gBAAgB,UAAU,CAAC,CAAC,CAAC,CAAC;AAC9B,gBAAgB,OAAO,CAAC,SAAS;AACjC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACrB;AACA,YAAY,MAAM,CAAC,UAAU,CAAC;AAC9B,gBAAgB,IAAI,CAAC,OAAO,CAAC;AAC7B,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;AACpD,YAAY,EAAE;AACd;AACA,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5D,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG;AACrB,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG;AAC1B;AACA,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE;AAC5B,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACvD;AACA,QAAQ,OAAO,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAChD,QAAQ,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C;AACA,QAAQ,OAAO,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAC9D,QAAQ,OAAO,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAC/D,QAAQ,OAAO,CAAC,KAAK,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,MAAM,EAAE;AAC/C,QAAQ,OAAO,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM;AACtD,QAAQ,OAAO,CAAC,KAAK,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO;AACvD,QAAQ,OAAO,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;AAClD,QAAQ,OAAO,CAAC,KAAK,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE;AAC5C,QAAQ,EAAE,yBAAyB,CAAC,CAAC,OAAO,CAAC,EAAE;AAC/C;AACA,QAAQ,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;AACpD,YAAY,OAAO,CAAC,YAAY,OAAO,CAAC;AACxC,YAAY,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AACxD,YAAY,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;AACxD,YAAY,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9C,gBAAgB,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AACrD,YAAY,EAAE;AACd,YAAY,cAAc,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,gBAAgB,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AAChD,oBAAoB,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;AACjD,oBAAoB,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AAC3D,oBAAoB,GAAG,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG;AACtC;AACA,gBAAgB,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,EAAE;AAClD,qBAAqB,KAAK,CAAC,qBAAqB,CAAC,EAAE;AACnD,qBAAqB,OAAO,CAAC,QAAQ,CAAC,EAAE;AACxC,qBAAqB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;AAChF,oBAAoB,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5C,oBAAoB,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE;AAC5C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC,CAAC,EAAE;AACZ;AACA,QAAQ,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,EAAE;AAC5C;AACA,QAAQ,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC;AACpC;AACA,QAAQ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE;AACpC;AACA,IAAI,CAAC;AACL,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACnF,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACvB;AACA,EAAE;AACF;AACA,EAAE,MAAM,CAAC,CAAC,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,cAAc,CAAC,SAAS,CAAC,GAAG;AACxI;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjC,QAAQ,GAAG,CAAC,OAAO,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;AACxE,YAAY,UAAU,GAAG,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;AAClE,YAAY,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AAClF,YAAY,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACnF,YAAY,UAAU,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACxF,YAAY,SAAS,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACvF,YAAY,MAAM,CAAC;AACnB;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACjD,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AACzC,gBAAgB,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE;AAC/D,YAAY,CAAC;AACb,YAAY,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC;AAC3C,YAAY,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE;AAC3D;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAChD,gBAAgB,EAAE,KAAK,CAAC,IAAI;AAC5B,gBAAgB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACtE,gBAAgB,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC7E,oBAAoB,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAChF,oBAAoB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACnE,oBAAoB,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;AAC9D,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACtE,oBAAoB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACnE,oBAAoB,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;AAC9D,gBAAgB,CAAC;AACjB,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACvE,gBAAgB,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC7E,oBAAoB,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACjF,oBAAoB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAClE,oBAAoB,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;AAC9D,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAClD,oBAAoB,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACtE,oBAAoB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAClE,oBAAoB,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;AAC9D,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AACpC,YAAY,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE;AAC1E,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACzB,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;AACxC,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE;AAC5D,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,KAAK,CAAC;AACrB,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO;AAC/B,IAAI,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACzB,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;AAC/B,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;AAC7C,YAAY,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG;AAC5C,UAAU,CAAC;AACX,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3B,YAAY,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE;AAC9D,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,CAAC,CAAC,EAAE;AACJ;AACA;AACA;AACA;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,EAAE;AACH,QAAQ,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC/B;AACA,IAAI,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACnF,QAAQ,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AAClF,QAAQ,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AAC9E,QAAQ,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AAC/E,QAAQ,UAAU,GAAG,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;AAC9D,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACzB,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5C,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,gBAAgB,EAAE,OAAO;AACzB,gBAAgB,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,oBAAoB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAClG,oBAAoB,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACzF,gBAAgB,CAAC;AACjB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,gBAAgB,EAAE,OAAO;AACzB,gBAAgB,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,oBAAoB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAClG,oBAAoB,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACzF,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,gBAAgB,EAAE,OAAO;AACzB,gBAAgB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,oBAAoB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAChG,oBAAoB,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACxF,gBAAgB,CAAC;AACjB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,gBAAgB,EAAE,OAAO;AACzB,gBAAgB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtC,oBAAoB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAChG,oBAAoB,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACxF,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,IAAI,MAAM,CAAC,KAAK,CAAC;AACjB;AACA,CAAC;AACD;AACA;AACA;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,EAAE;AACH,QAAQ,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACjC,IAAI,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACnF,QAAQ,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AAClF,QAAQ,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AAC9E,QAAQ,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AAC/E,QAAQ,UAAU,GAAG,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;AAC9D,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACzB,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5C,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,gBAAgB,EAAE,OAAO;AACzB,gBAAgB,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,oBAAoB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAClG,oBAAoB,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACzF,gBAAgB,CAAC;AACjB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,gBAAgB,EAAE,OAAO;AACzB,gBAAgB,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,oBAAoB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAClG,oBAAoB,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACzF,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,gBAAgB,EAAE,MAAM,CAAC,EAAE;AAC3B,gBAAgB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AAChE,oBAAoB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAChG,oBAAoB,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACxF,gBAAgB,CAAC;AACjB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,gBAAgB,EAAE,MAAM,CAAC,IAAI;AAC7B,gBAAgB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtC,oBAAoB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAChG,oBAAoB,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACxF,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,IAAI,EAAE,OAAO,CAAC,KAAK;AACnB,IAAI,MAAM,CAAC,KAAK,CAAC;AACjB,CAAC;AACD;AACA;AACA,QAAQ,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAClD,IAAI,GAAG,CAAC,SAAS,CAAC;AAClB,QAAQ,iBAAiB,CAAC;AAC1B,QAAQ,eAAe,CAAC;AACxB,QAAQ,UAAU,CAAC;AACnB,QAAQ,KAAK,CAAC;AACd,QAAQ,CAAC,CAAC;AACV,QAAQ,OAAO,CAAC;AAChB,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACzC,QAAQ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC;AACrC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;AACtC,IAAI,CAAC;AACL,IAAI,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,IAAI,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvF,IAAI,iBAAiB,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,iBAAiB,CAAC;AAC5D,IAAI,iBAAiB,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC;AACtE;AACA,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACxF,QAAQ,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE;AAClC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACrC,YAAY,GAAG,CAAC,cAAc,CAAC;AAC/B,YAAY,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE;AACjE,YAAY,EAAE,CAAC,CAAC,kBAAkB,CAAC,0BAA0B,CAAC,CAAC,CAAC;AAChE,gBAAgB,cAAc,CAAC,CAAC,CAAC,CAAC;AAClC,oBAAoB,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE;AAClC,oBAAoB,GAAG,CAAC,CAAC,kBAAkB,CAAC,0BAA0B;AACtE,gBAAgB,EAAE;AAClB,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,cAAc,CAAC,CAAC,CAAC,kBAAkB,CAAC;AACpD,YAAY,CAAC;AACb,YAAY,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AACxC,gBAAgB,EAAE,CAAC,qBAAqB,OAAO,CAAC,EAAE,CAAC;AACnD,gBAAgB,WAAW,CAAC,YAAY,CAAC,cAAc,EAAE;AACzD,gBAAgB,OAAO,CAAC,gBAAgB,OAAO,CAAC;AAChD,gBAAgB,kBAAkB,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;AACxD,gBAAgB,aAAa,CAAC,UAAU,KAAK,CAAC;AAC9C,gBAAgB,eAAe,CAAC,QAAQ,KAAK,CAAC;AAC9C,gBAAgB,qBAAqB,CAAC,EAAE,KAAK,CAAC;AAC9C,gBAAgB,mBAAmB,CAAC,IAAI,KAAK,CAAC;AAC9C,gBAAgB,eAAe,CAAC,QAAQ,IAAI,CAAC;AAC7C,gBAAgB,SAAS,CAAC,cAAc,CAAC,CAAC;AAC1C,gBAAgB,aAAa,CAAC,UAAU,CAAC;AACzC,YAAY,CAAC,CAAC,EAAE;AAChB;AACA,YAAY,UAAU,CAAC,aAAa,WAAW,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAC/E,YAAY,UAAU,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE;AAC/E,YAAY,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE;AACjE;AACA,YAAY,KAAK,eAAe,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,KAAK,CAAC;AACjE,YAAY,KAAK,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE;AAC7C,YAAY,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,EAAE;AACxC,YAAY,KAAK,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG,EAAE;AACxC,YAAY,KAAK,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE;AACxC,YAAY,KAAK,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE;AAC3C,YAAY,KAAK,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM;AAClD,YAAY,KAAK,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO;AACnD,YAAY,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;AAC9C,YAAY,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC,SAAS,CAAC;AAC5C,YAAY,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC,CAAC,OAAO,EAAE;AAC5C,YAAY,KAAK,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAClE,YAAY,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACnE;AACA,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC;AAC1E,YAAY,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;AACzE,gBAAgB,OAAO,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC;AAClD,gBAAgB,aAAa,CAAC,CAAC,IAAI;AACnC,YAAY,CAAC,CAAC,EAAE;AAChB;AACA,YAAY,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC;AACjE,gBAAgB,UAAU,CAAC,aAAa;AACxC,YAAY,EAAE;AACd;AACA,YAAY,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;AACvD;AACA,YAAY,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AACvC,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,CAAC;AACD;AACA;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,EAAE;AACH,QAAQ,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC;AAC5C;AACA,IAAI,IAAI,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACxC;AACA,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE;AAC9C,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE;AACxC;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACxC;AACA,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AAC3C,QAAQ,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AAC3C;AACA,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ;AACA,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AAC7C,QAAQ,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AACzC;AACA,IAAI,CAAC;AACL,IAAI,MAAM,CAAC,KAAK,CAAC;AACjB,CAAC;AACD;AACA;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,EAAE;AACH,QAAQ,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC/B,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC;AAC5C;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACxC;AACA,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AAC5C,QAAQ,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACxF;AACA,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ;AACA,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AAC9C,QAAQ,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACtF;AACA,IAAI,CAAC;AACL,IAAI,MAAM,CAAC,KAAK,CAAC;AACjB,CAAC;AACD;AACA;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,EAAE;AACH,QAAQ,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7B,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;AACnC;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpF,QAAQ,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClC,YAAY,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK;AAC/B,gBAAgB,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAClH,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK;AACjC,gBAAgB,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACnH,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK;AACjC,gBAAgB,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACnH,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK;AAClC,gBAAgB,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAClH,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,OAAO,CAAC;AACpB,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;AACvE,gBAAgB,MAAM,CAAC,IAAI,CAAC;AAC5B,QAAQ,CAAC;AACT,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,CAAC;AACL,CAAC;AACD;AACA;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,EAAE;AACH,QAAQ,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;AACnC;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpF,QAAQ,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClC,YAAY,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK;AAC1B,gBAAgB,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAClH,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;AAC1B,gBAAgB,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACnH,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE;AAC1B,YAAY,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;AACzB,YAAY,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACxB,gBAAgB,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAClH,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;AACzB,YAAY,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACxB,gBAAgB,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACnH,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACxB,gBAAgB,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACnH,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;AACzB,gBAAgB,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAClH,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAY,OAAO,CAAC;AACpB,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;AACvE,gBAAgB,MAAM,CAAC,IAAI,CAAC;AAC5B,QAAQ,CAAC;AACT,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,CAAC;AACL,CAAC;AACD;AACA,EAAE,aAAa,GAAG;;ACrmBlB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW;AAC9B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW;AACrB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG;AAC5F,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM;AAC3E,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;AACtB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI;AAC9B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;AAC9C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;AAC9C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE;AACvD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE;AACvD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;AAC5D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;AAC7D,CAAC,EAAE;AACH,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACrE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AAClD;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;AACvC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAChC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,WAAW,CAAC;AAC3C,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC7B,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;AACxC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAChC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,WAAW,CAAC;AAC3C,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC7B,EAAE;AACF;AACA,EAAE,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE;AACtD;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;ACtEpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM;AACzB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC;AAC3D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;AACzF,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC;AACtD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC;AACrF,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;AAC3B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC;AACjE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU;AAChF,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI;AACpF,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;AACjD,CAAC,EAAE;AACH,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAChC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACzB;AACA,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AACxC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACvE,QAAQ,EAAE,WAAW,CAAC,UAAU;AAChC,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC;AACnB,YAAY,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACtE,gBAAgB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,gBAAgB,SAAS,CAAC;AAC1B,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC;AAChC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe;AAC/C,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AAC9C,aAAa,EAAE;AACf,YAAY,eAAe,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,gBAAgB,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC;AAC3C,gBAAgB,CAAC,CAAC,CAAC,CAAC;AACpB,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC;AAC7C,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa;AAC7C,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AAC9C,aAAa,EAAE;AACf,YAAY,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,gBAAgB,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;AACzC,gBAAgB,CAAC,CAAC,CAAC;AACnB,QAAQ,EAAE;AACV,IAAI,CAAC;AACL;AACA,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC;AAClG,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG;AACpF;AACA,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC;AAC7F,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG;AACpG;AACA,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;AAC9B,QAAQ,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC,QAAQ,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;AACnC,IAAI,CAAC;AACL;AACA,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE;AACnC;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAC/B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AACtC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC/B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI;AAC9B,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACpB,QAAQ,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACpD,YAAY,IAAI,CAAC,OAAO,CAAC,CAAC;AAC1B,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACxC,QAAQ,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY;AACrD,IAAI,EAAE;AACN;AACA,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AACpE,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,GAAG;AACjF;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC7B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AACtC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC/B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI;AAC9B,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClB,QAAQ,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;AAClC,QAAQ,IAAI,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI;AAChC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AAC9B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AACtC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC/B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI;AAC9B,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACnB,QAAQ,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;AAClC,QAAQ,IAAI,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI;AAChC,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AAC5B,QAAQ,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;AAC1D,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;AAC5D,QAAQ,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;AAC9D,IAAI,CAAC;AACL,EAAE;AACF;AACA,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE;AAC5C,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACtB;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AAC7B,KAAK,EAAE;AACP,IAAI,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACjC,QAAQ,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5D,YAAY,EAAE,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,GAAG;AAC9F;AACA,QAAQ,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AAC3E,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AACzE;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AAChC,YAAY,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;AAC9D,YAAY,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;AAChE,YAAY,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;AAClE,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AAC7B,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAClC,QAAQ,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5D,YAAY,EAAE,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,GAAG;AAC/F;AACA,QAAQ,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;AAC/C,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;AAC9C,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AACnC,QAAQ,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC;AACxE;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AAChC,YAAY,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;AAC9D,YAAY,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;AAChE,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC5B,KAAK,EAAE;AACP,IAAI,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChC,QAAQ,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC;AACnC,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC;AACnC;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AAChC,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/E,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,GAAG;AACxG;AACA,YAAY,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;AAC9D,YAAY,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;AAChE,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,cAAc,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AACrC,QAAQ,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC;AAClC;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AAChC,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3G,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,GAAG;AAC/G;AACA,YAAY,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;AAC9D,YAAY,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;AAChE,YAAY,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;AAClE,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,SAAS;AAC9D,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACxB,QAAQ,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG;AACrC;AACA,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC;AACpC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AAChC,YAAY,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;AAC9C,YAAY,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;AAChD,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;AAC1C,YAAY,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;AAC5C,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AACpE,YAAY,WAAW,CAAC,CAAC;AACzB,YAAY,UAAU,CAAC,CAAC;AACxB,gBAAgB,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC9C,gBAAgB,SAAS,CAAC;AAC1B,oBAAoB,IAAI,CAAC,eAAe,CAAC;AACzC,oBAAoB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7D,oBAAoB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC1D,gBAAgB,EAAE;AAClB;AACA,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;AAC1C,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AAChC,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE;AACxD,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC;AAC9C,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;AAC9C,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK;AACxD,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,SAAS;AAClE,KAAK,EAAE;AACP,IAAI,eAAe,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACjC,QAAQ,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;AACxD,IAAI,CAAC;AACL,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,EAAE;AACH,QAAQ,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;AACzC,CAAC;AACD;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;ACpQpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW;AAC9B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD;AACA,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,IAAI;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ;AAClB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;AACpD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;AACvD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC;AAC5D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;AACjF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;AAC7F,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS;AACjF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC;AAChF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC;AAC7E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC;AAC/G,CAAC,EAAE;AACH,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC7B;AACA,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1B,QAAQ,OAAO,CAAC,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC;AAC5C,QAAQ,KAAK,CAAC,CAAC,IAAI;AACnB,IAAI,EAAE,CAAC,OAAO,EAAE;AAChB;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC;AACxD,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK;AAC5B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC;AACxC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACtB,CAAC;AACD;AACA,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACtB,IAAI,QAAQ,CAAC,CAAC,IAAI,CAAC;AACnB;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC;AAC5B,KAAK,CAAC,CAAC,CAAC,MAAM;AACd,KAAK,EAAE;AACP,IAAI,KAAK,CAAC,CAAC,QAAQ,GAAG;AACtB,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACxB,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;AACnC;AACA,QAAQ,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG;AACjC;AACA,QAAQ,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,GAAG;AACvC,YAAY,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;AAC9B,QAAQ,EAAE;AACV,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC9D,YAAY,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE;AACjD,YAAY,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;AAC/B,QAAQ,EAAE;AACV;AACA,QAAQ,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,GAAG;AAClD,YAAY,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE;AAC1D,YAAY,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;AAC/B,QAAQ,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE;AACzB;AACA,QAAQ,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE;AAC3E,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;AAC5F,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AAChC,YAAY,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE;AAC9C,gBAAgB,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AAC9B,gBAAgB,eAAe,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC;AAC1D,gBAAgB,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;AAC1C,gBAAgB,YAAY,CAAC,CAAC,CAAC,WAAW,EAAE;AAC5C,gBAAgB,OAAO,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAC5C,oBAAoB,GAAG,CAAC,GAAG,CAAC;AAC5B,oBAAoB,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACrD,oBAAoB,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACxD,oBAAoB,EAAE,CAAC,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,aAAa;AACzG,oBAAoB,GAAG,CAAC,CAAC;AACzB,wBAAwB,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,GAAG;AAClE,oBAAoB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjC,wBAAwB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC3C,4BAA4B,MAAM,CAAC,WAAW,CAAC,EAAE;AACjD,4BAA4B,MAAM,CAAC,iBAAiB,CAAC,EAAE;AACvD,4BAA4B,MAAM,CAAC,cAAc,CAAC,EAAE;AACpD,4BAA4B,MAAM,CAAC,aAAa;AAChD,wBAAwB,EAAE;AAC1B,wBAAwB,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;AACpE,4BAA4B,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,GAAG;AACvD,4BAA4B,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE;AACxD,4BAA4B,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,GAAG;AAC/C,wBAAwB,CAAC;AACzB,oBAAoB,CAAC;AACrB,oBAAoB,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;AAC9F,oBAAoB,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,wBAAwB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,GAAG;AAChE,wBAAwB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;AAC3C,oBAAoB,CAAC;AACrB,oBAAoB,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;AACjG,oBAAoB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;AAC/F,oBAAoB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,eAAe,CAAC,GAAG,EAAE;AACpF,oBAAoB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AACzC,gBAAgB,EAAE;AAClB,gBAAgB,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAC1C,oBAAoB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE;AACrE,oBAAoB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;AACvC,gBAAgB,CAAC;AACjB,YAAY,GAAG;AACf;AACA,YAAY,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC;AAChE,YAAY,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACrC,gBAAgB,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG;AACrC;AACA,gBAAgB,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS;AAChE,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACtD,oBAAoB,SAAS,GAAG;AAChC,gBAAgB,CAAC;AACjB,YAAY,EAAE;AACd,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;AACnD,gBAAgB,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC;AAChE,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AACtC,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;AAClC,QAAQ,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3E,QAAQ,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;AAC1B,YAAY,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9B,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACzB,YAAY,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE;AAC5C,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE;AAC5B,IAAI,CAAC;AACL;AACA,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW;AACrB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC;AACtF,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC;AACtE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC;AAC1D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AACnJ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC;AAC7G,CAAC,EAAE;AACH,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACnC;AACA,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1B,QAAQ,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC,gBAAgB,CAAC;AAC5D,QAAQ,OAAO,CAAC,QAAQ,EAAE,gBAAgB,CAAC,OAAO,CAAC;AACnD,QAAQ,QAAQ,CAAC,OAAO,GAAG;AAC3B,QAAQ,cAAc,CAAC,CAAC,CAAC;AACzB,IAAI,EAAE,CAAC,OAAO,EAAE;AAChB;AACA,EAAE;AACF;AACA,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE;AACjD,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC3B;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;AACjD,KAAK,CAAC,CAAC,CAAC,MAAM;AACd,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;AACtD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC;AAChE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;AACrF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;AACjG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS;AAC7F,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC,IAAI;AAC9F,KAAK,CAAC,CAAC,QAAQ,CAAC;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC;AACpF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC;AACjF,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAC/B,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,YAAY,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AACtC,gBAAgB,WAAW,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE;AAC1D,YAAY,EAAE;AACd,YAAY,UAAU,CAAC,CAAC,CAAC,CAAC;AAC1B,gBAAgB,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;AACjC,gBAAgB,YAAY,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;AACnD,gBAAgB,WAAW,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/E,gBAAgB,iBAAiB,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC;AAC7D,gBAAgB,mBAAmB,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC;AACjE,gBAAgB,QAAQ,CAAC,CAAC,QAAQ,CAAC;AACnC,gBAAgB,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AACrC,gBAAgB,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO;AACrC,YAAY,EAAE;AACd,YAAY,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,EAAE;AAC9C;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACtE,YAAY,MAAM,CAAC,KAAK,GAAG;AAC3B,YAAY,IAAI,CAAC,cAAc,GAAG;AAClC,QAAQ,CAAC;AACT,QAAQ,IAAI,CAAC,CAAC;AACd,YAAY,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACzC,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7D,KAAK,CAAC,CAAC,CAAC,MAAM;AACd,KAAK,EAAE;AACP,IAAI,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACvB,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACzD,YAAY,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE;AACvC,YAAY,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,gBAAgB,GAAG,CAAC,KAAK,GAAG;AAC5B,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG;AAC3B,IAAI,CAAC;AACL,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC;AACrC,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC;AACjD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;AAChD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC;AACrD,CAAC,EAAE;AACH,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC7C,IAAI,GAAG,CAAC,OAAO,CAAC;AAChB;AACA,IAAI,MAAM,CAAC,cAAc,GAAG;AAC5B;AACA,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtG,QAAQ,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,GAAG;AAC1C,QAAQ,OAAO,CAAC,KAAK,GAAG;AACxB,QAAQ,MAAM,CAAC,cAAc,GAAG;AAChC,IAAI,CAAC;AACL;AACA,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE;AACnD,CAAC;AACD;AACA,EAAE,aAAa,GAAG;;AC3QlB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI;AACvB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;AACd,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;AAC7D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;AAC9C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;AAC9C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,UAAU;AAC1E,CAAC,CAAC,MAAM,WAAW,CAAC;AACpB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG;AAC5E,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;AACnC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;AACpD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,wBAAwB,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE;AAC/E,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;AAC3C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAChG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,UAAU,EAAE;AACjG,CAAC,EAAE;AACH,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC3F,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC7B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;AACzB,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;AAChC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACzB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACrB,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;AAChC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACzB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACrB,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW;AACtD,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM;AAC1C,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;AAC1B,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC;AAChF,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM;AAC/B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;AAC1B,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;AACpC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG;AAC3B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC;AACvB,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;AAChF,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,wBAAwB,CAAC,CAAC,SAAS;AACnD,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/B,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;AAC9D,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY;AACrC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC;AACrC,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;AAC9D,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AACnC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC;AACnC,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;AAC1C,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAChC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;AAC3B,QAAQ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE;AAC1E,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AACjC,IAAI,CAAC;AACL,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AAC3B,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM;AAC/B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC;AACzB,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;AAC5B,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AAChC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AACzB;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI;AACzC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AAChC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC;AAC3B,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;AAC1C,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU;AACnC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3B,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;AACtC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC7B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,KAAK,MAAM,CAAC,CAAC,IAAI,CAAC;AAC3B;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;AACvC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC7B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,KAAK,MAAM,CAAC,CAAC,IAAI,CAAC;AAC3B,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC;AACjD,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ;AAC7C,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC;AAC3B,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC;AAC7C,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,IAAI;AACzC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,IAAI,CAAC;AAC3B,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC9C,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU;AAClC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3B,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;AAC/C,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAC/B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC;AAC3B,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;AAChE,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC;AAC/B,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe;AACvC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC,IAAI,CAAC;AAClC,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;AACzC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU;AAClC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3B;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC;AAClD,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU;AACnC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,UAAU,KAAK,CAAC,CAAC,KAAK,CAAC;AAChC;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa;AACrC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5B;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;AACnE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW;AACpC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7B;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY;AACrC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC;AAC9B,EAAE;AACF;AACA,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;AAC1C,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACpB;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,KAAK,CAAC,CAAC,UAAU,CAAC;AAClB,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;AACxB,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC1B,QAAQ,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACxD,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,uBAAuB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACzC,QAAQ,MAAM,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,GAAG;AAC1D,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC;AAC7C,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS;AACjC,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACrC,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACrC,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC;AAC3B,gBAAgB,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE;AACnF,gBAAgB,IAAI,CAAC,QAAQ,IAAI;AACjC,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC7B,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC;AAC3B,gBAAgB,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG;AACvE,gBAAgB,IAAI,CAAC,QAAQ,EAAE;AAC/B,YAAY,EAAE;AACd,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,QAAQ,EAAE,eAAe,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC;AACxE;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC9B,YAAY,IAAI,CAAC,OAAO,8BAA8B,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AACtF,YAAY,IAAI,CAAC,UAAU,2BAA2B,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,GAAG,SAAS,GAAG;AACrG,YAAY,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE;AAC3E,YAAY,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,eAAe,CAAC,CAAC,CAAC,GAAG,GAAG;AAC/D,YAAY,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,cAAc,CAAC,CAAC,CAAC,GAAG,GAAG;AAC/D;AACA,YAAY,IAAI,CAAC,KAAK,qBAAqB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;AAChE,YAAY,IAAI,CAAC,KAAK,CAAC,QAAQ,YAAY,CAAC,CAAC,CAAC,QAAQ,EAAE;AACxD,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACrD,YAAY,SAAS,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AAClD,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC3D,YAAY,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;AACxD,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACpD,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACpD,QAAQ,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAChD,QAAQ,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAChD;AACA,QAAQ,EAAE,iBAAiB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AAC1D,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;AAClD,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAC9B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;AAC9E,KAAK,CAAC,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;AAChD,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3E,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI;AACrE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM;AACtE,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACvE;AACA,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,GAAG,iBAAiB,EAAE;AAChE,YAAY,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,iBAAiB,EAAE;AAC5D,YAAY,QAAQ,CAAC;AACrB;AACA,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACxD,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC;AAC3B,gBAAgB,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE;AACrF,gBAAgB,IAAI,CAAC,QAAQ,IAAI;AACjC,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,GAAG;AAChF;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE;AACzC,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC;AAC3B,gBAAgB,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG;AACvE,gBAAgB,IAAI,CAAC,QAAQ,EAAE;AAC/B,YAAY,EAAE;AACd;AACA,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,OAAO,CAAC,IAAI,GAAG;AACvB;AACA,QAAQ,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AAC3C;AACA,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,YAAY,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK;AAC7C,YAAY,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE;AAC7C,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;AACrC,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AAC3C,YAAY,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ;AAC3C,YAAY,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE;AAChD,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC;AACpE,QAAQ,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO;AAC3E,QAAQ,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG;AAC3D,QAAQ,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACvE,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,uBAAuB,GAAG,CAAC,CAAC;AAC1E,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ;AAChE,YAAY,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS;AAChD,YAAY,OAAO,CAAC,SAAS,CAAC;AAC9B,gBAAgB,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,gBAAgB,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,gBAAgB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,gBAAgB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1B,YAAY,EAAE;AACd,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY;AACzE,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK;AAChD,QAAQ,cAAc,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,GAAG;AAC3E;AACA,QAAQ,OAAO,CAAC,SAAS,CAAC;AAC1B,YAAY,QAAQ,CAAC,MAAM,CAAC;AAC5B,YAAY,CAAC,CAAC;AACd,YAAY,CAAC,CAAC;AACd,YAAY,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC;AAClC,YAAY,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;AACnC,YAAY,QAAQ,CAAC,CAAC,CAAC;AACvB,YAAY,QAAQ,CAAC,CAAC,CAAC;AACvB,YAAY,IAAI,CAAC,CAAC,CAAC;AACnB,YAAY,IAAI,CAAC,CAAC;AAClB,QAAQ,EAAE;AACV;AACA,QAAQ,OAAO,CAAC,OAAO,GAAG;AAC1B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;AACvD,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;AACtB,KAAK,EAAE;AACP,IAAI,wBAAwB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC1C,QAAQ,GAAG,CAAC,OAAO,CAAC;AACpB,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACpC,YAAY,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,GAAG;AACjE,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AACpC,YAAY,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AACrC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC;AAC3B,gBAAgB,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE;AAC5F,gBAAgB,IAAI,CAAC,QAAQ,IAAI;AACjC,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE;AAC1E,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC;AACpG,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC;AAC9C,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC;AACnE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACpC,KAAK,EAAE;AACP,IAAI,8BAA8B,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACnF,QAAQ,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG;AAC/F,QAAQ,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE;AACnG,QAAQ,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;AACjE,QAAQ,EAAE,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;AAC1G,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;AAChF,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;AAChF,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;AACvC,YAAY,IAAI,CAAC,QAAQ;AACzB,gBAAgB,CAAC,KAAK,GAAG,iBAAiB,CAAC;AAC3C,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;AAClC,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,oBAAoB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjC,gBAAgB,EAAE;AAClB,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;AACvC,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACxB,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC9D,YAAY,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;AACtE,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACxD,YAAY,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AAChE,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC;AAC/B,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B,QAAQ,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,KAAK,CAAC;AAChC,QAAQ,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC;AAChC,IAAI,CAAC;AACL,EAAE;AACF;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;ACrbpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO;AAC1B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,GAAG,CAAC,CAAC;AACd;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;AAC9E,KAAK,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC;AACpB,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ;AAC1E,KAAK,CAAC,CAAC,aAAa,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB;AAC/B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,SAAS;AACnC,KAAK,CAAC,CAAC,CAAC,MAAM;AACd,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AAChC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAClC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG;AAC7B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS;AACnC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AAC/B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY;AACtC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AAChC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AACrC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI;AAC9B,KAAK,EAAE;AACP,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC;AACrC;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ;AAClE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,mBAAmB;AAClC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,CAAC,CAAC,CAAC,MAAM;AACd,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;AAC/E,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI;AAC/E,KAAK,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC;AAC/E,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;AAC1E,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;AACjE,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC;AAClF,KAAK,EAAE;AACP,IAAI,EAAE,mBAAmB,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE;AAC5C,QAAQ,WAAW,CAAC,CAAC,CAAC,CAAC;AACvB,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC;AACjB,QAAQ,YAAY,CAAC,CAAC,CAAC;AACvB,IAAI,GAAG;AACP;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO;AACrB,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;AACvF,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC9B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAC9B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO;AACvC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG;AAC7E,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;AAC7E,KAAK,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO;AAC9E,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC;AAC7E,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,KAAK;AAC/E,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC;AACzC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,aAAa,CAAC,SAAS,CAAC,QAAQ,CAAC;AAC5F,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ;AACnF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACrE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE;AAC3E,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU;AAC5E,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC1E,KAAK,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ;AAC3E,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI;AAChF,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ;AAC7E,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI;AACjF,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,aAAa,CAAC,mBAAmB,CAAC,KAAK,CAAC;AACtF,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;AAClD,KAAK,EAAE;AACP,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AACxD;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAC3E,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ;AAChD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,IAAI;AAC5C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AACnC,SAAS,EAAE;AACX;AACA,QAAQ,GAAG,CAAC,OAAO,CAAC;AACpB,QAAQ,EAAE,CAAC,GAAG,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC;AACvC,YAAY,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;AAC9B,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,OAAO,CAAC,CAAC,CAAC,CAAC;AACvB,gBAAgB,OAAO,CAAC,CAAC,OAAO,CAAC;AACjC,gBAAgB,QAAQ,CAAC,CAAC,QAAQ,CAAC;AACnC,gBAAgB,SAAS,CAAC,CAAC,SAAS;AACpC,YAAY,EAAE;AACd,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;AACvC,QAAQ,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;AAC3C,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE;AAC5B,IAAI,EAAE;AACN;AACA,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;AACjD,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC3B;AACA,QAAQ,EAAE,CAAC,OAAO;AAClB,QAAQ,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAClC,YAAY,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;AAC7C,YAAY,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAC9D,gBAAgB,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;AACzD,YAAY,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACzC,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAClE,gBAAgB,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;AAC3C;AACA,YAAY,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY;AAC/E,YAAY,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AAC5E;AACA,YAAY,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU;AAC9E,YAAY,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AAC/E;AACA,YAAY,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,mBAAmB,CAAC,KAAK,CAAC;AACpF;AACA,YAAY,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK;AAC7D,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAClD,gBAAgB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;AACjD,gBAAgB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;AACnD,gBAAgB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,GAAG;AAC3D,gBAAgB,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,QAAQ,CAAC;AACtD,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC;AACrE,YAAY,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;AACtE,YAAY,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AACrC,gBAAgB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE;AAC3E,YAAY,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;AAC1C,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO;AACjE,SAAS,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;AAC9C,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ;AAChD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,IAAI;AAC5C,SAAS,EAAE;AACX,QAAQ,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1C,YAAY,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE;AACpE,YAAY,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;AAC9B,gBAAgB,MAAM,CAAC;AACvB,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC,CAAC;AACpD,gBAAgB,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;AAC5C,gBAAgB,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;AACrC,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC,CAAC;AAClD,gBAAgB,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC7C,gBAAgB,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;AACrC,YAAY,CAAC;AACb,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,EAAE;AACX,QAAQ,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC7B,YAAY,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AACvC,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;AACnC;AACA,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;AACrC,gBAAgB,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,OAAO,EAAE;AACxD,gBAAgB,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO;AACjF,gBAAgB,EAAE,KAAK;AACvB,gBAAgB,EAAE,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC;AAChD,oBAAoB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AAC3C,oBAAoB,EAAE,OAAO,CAAC,iBAAiB,CAAC,YAAY,CAAC;AAC7D,oBAAoB,EAAE,IAAI,OAAO,CAAC;AAClC,oBAAoB,EAAE,IAAI,OAAO,CAAC,eAAe;AACjD,oBAAoB,IAAI;AACxB,oBAAoB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE;AACvD,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ;AACxC,YAAY,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B;AACA,YAAY,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;AAC3B,YAAY,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG;AAC5B,YAAY,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG;AAChC;AACA,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACtC,gBAAgB,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG;AACjC,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACvC,gBAAgB,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG;AAClC,YAAY,CAAC;AACb,YAAY,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,8BAA8B,CAAC;AACvE,gBAAgB,CAAC,eAAe,GAAG;AACnC,YAAY,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,8BAA8B,CAAC;AACjE,gBAAgB,CAAC,SAAS,GAAG;AAC7B,YAAY,EAAE,CAAC,CAAC,mBAAmB,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC;AACvD,gBAAgB,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,GAAG;AAChD,gBAAgB,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG;AAC1C,YAAY,CAAC;AACb,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS;AACrC,SAAS,EAAE;AACX,QAAQ,QAAQ,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AACjD,YAAY,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AACvC,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AACnD,gBAAgB,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;AAChE,gBAAgB,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;AAC/D,gBAAgB,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;AAC9D,gBAAgB,SAAS,CAAC,WAAW,CAAC,OAAO,EAAE;AAC/C;AACA,gBAAgB,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI;AAC1E,gBAAgB,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;AACjD,gBAAgB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE;AAC7E,gBAAgB,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC;AAC7E,gBAAgB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,OAAO,EAAE;AACtD,YAAY,CAAC;AACb;AACA,YAAY,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,QAAQ,EAAE;AAC5E;AACA,YAAY,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,QAAQ,CAAC;AACpD,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC;AACxD,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC;AAChD;AACA,YAAY,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS;AAC9E,YAAY,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO;AAC5D,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAC9B,gBAAgB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE;AAC1D,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;AACvC,gBAAgB,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAC/C,gBAAgB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAC9C,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1C,oBAAoB,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AAChD,gBAAgB,CAAC;AACjB,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3C,oBAAoB,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;AACjD,gBAAgB,CAAC;AACjB,gBAAgB,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,8BAA8B,CAAC;AAC3E,oBAAoB,CAAC,eAAe,GAAG;AACvC,gBAAgB,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,8BAA8B,CAAC;AACrE,oBAAoB,CAAC,SAAS,GAAG;AACjC,gBAAgB,EAAE,CAAC,CAAC,mBAAmB,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC;AAC3D,oBAAoB,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACjC,wBAAwB,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,GAAG;AAChF,wBAAwB,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AAC3E,oBAAoB,CAAC,CAAC,IAAI,CAAC,CAAC;AAC5B,wBAAwB,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,GAAG;AACxD,wBAAwB,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG;AAClD,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB;AACA,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AAC/C,oBAAoB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;AAC5C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,OAAO;AAClB,QAAQ,0BAA0B,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AACxD,YAAY,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE;AACxE,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE;AACvD,YAAY,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE;AACxC;AACA,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,YAAY,EAAE,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;AACnC,gBAAgB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC,CAAC;AAC1E,gBAAgB,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC;AAC5E,gBAAgB,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC;AACnD,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,mBAAmB,CAAC,YAAY,CAAC,EAAE;AAC/E,oBAAoB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAClE,oBAAoB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AAClF,oBAAoB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE;AACnF,oBAAoB,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,UAAU,GAAG;AACxD,oBAAoB,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,GAAG;AACjD,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,oBAAoB,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;AAC9C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,CAAC;AACpB,gBAAgB,QAAQ,CAAC,CAAC,QAAQ,CAAC;AACnC,gBAAgB,IAAI,CAAC,CAAC,IAAI,CAAC;AAC3B,gBAAgB,MAAM,CAAC,CAAC,MAAM;AAC9B,YAAY,EAAE;AACd,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,OAAO;AAClB,QAAQ,gBAAgB,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC9C,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACpC,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACrC,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9D,gBAAgB,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC;AACxE,oBAAoB,GAAG,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE;AAC1E,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1C,oBAAoB,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;AACzC,gBAAgB,CAAC;AACjB,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3C,oBAAoB,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;AAC1C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AACnC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;AAChE,gBAAgB,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE;AACzE,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1C,oBAAoB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACtC,gBAAgB,CAAC;AACjB,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3C,oBAAoB,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACvC,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE;AAC9C,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,OAAO;AAClB,QAAQ,eAAe,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAClD,YAAY,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE;AACzD,YAAY,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,cAAc,GAAG;AACnE,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,OAAO;AAClB,QAAQ,kBAAkB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5C,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACrD,YAAY,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE;AACpE,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;AAC7B,gBAAgB,EAAE,CAAC,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC,CAAC;AACxD,oBAAoB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;AAChD,oBAAoB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;AAC3C,gBAAgB,CAAC;AACjB,gBAAgB,EAAE,CAAC,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC,CAAC;AACtD,oBAAoB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;AACjD,oBAAoB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC5C,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,MAAM,CAAC;AAC1B,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,OAAO;AAClB,QAAQ,mBAAmB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACzC,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG;AAC5B,YAAY,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE;AACpE,YAAY,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;AAC9B,gBAAgB,MAAM,CAAC,MAAM,CAAC;AAC9B,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AACpC,gBAAgB,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AAChC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;AAC5C,gBAAgB,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;AACjC,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;AACnC,gBAAgB,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;AACjC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC7C,gBAAgB,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE;AACpC,YAAY,CAAC;AACb,YAAY,MAAM,CAAC,MAAM,CAAC;AAC1B,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACxC,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC1E,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW;AACnF,SAAS,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC;AAC3D,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,SAAS;AACrD,SAAS,EAAE;AACX,QAAQ,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAC/C,YAAY,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAClE,gBAAgB,QAAQ,CAAC,CAAC,QAAQ,CAAC;AACnC,gBAAgB,SAAS,CAAC,CAAC,SAAS;AACpC,YAAY,EAAE;AACd,YAAY,IAAI,CAAC,KAAK,EAAE;AACxB,gBAAgB,QAAQ,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;AAC5D,gBAAgB,SAAS,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAC5D,oBAAoB,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AACvD,gBAAgB,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AACtD,gBAAgB,WAAW,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC;AACrE,gBAAgB,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;AAChF,gBAAgB,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;AACpF,gBAAgB,YAAY,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY;AACvE,YAAY,GAAG;AACf,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW;AAC5E,SAAS,CAAC,CAAC,CAAC,QAAQ;AACpB,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ;AAChE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM;AACvD,SAAS,EAAE;AACX,QAAQ,SAAS,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AACvC,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;AACtC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,IAAI;AACvE,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;AACnC,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;AACrC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACpD,gBAAgB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE;AACnF,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACrC,oBAAoB,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACnC,gBAAgB,CAAC;AACjB,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACtC,oBAAoB,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACpC,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,YAAY,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,GAAG;AACjD,YAAY,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG;AAC9D,YAAY,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC;AACjD,gBAAgB,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG;AAC7E,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,OAAO;AAClB,QAAQ,wBAAwB,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC9D,YAAY,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE;AAC5B,gBAAgB,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AACzC,gBAAgB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC;AACpE,gBAAgB,MAAM,CAAC,MAAM,CAAC;AAC9B,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,mBAAmB,CAAC,YAAY,CAAC,CAAC,CAAC;AAC3E,gBAAgB,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK;AAClF,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAClE,oBAAoB,MAAM,CAAC,MAAM,CAAC;AAClC,gBAAgB,CAAC;AACjB,gBAAgB,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG;AACzE,gBAAgB,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACnD,gBAAgB,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,QAAQ,EAAE;AAChF,gBAAgB,MAAM,CAAC,QAAQ,CAAC,gCAAgC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC5E,oBAAoB,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC/C,oBAAoB,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC/C,oBAAoB,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3C,oBAAoB,eAAe,CAAC,IAAI,CAAC,CAAC,GAAG;AAC7C,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,WAAW,CAAC,IAAI;AAC/B,YAAY,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC;AACnD,gBAAgB,IAAI,CAAC,kBAAkB,CAAC,MAAM,GAAG;AACjD,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,EAAE,aAAa,GAAG;;AC7dlB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM;AACzB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE;AAC7E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;AACrD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AACnF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC;AACnF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;AACrD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AAC9G,CAAC,EAAE;AACH,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAChC;AACA,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AAC9E;AACA,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI;AACrE,IAAI,EAAE,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ;AAC9D,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,SAAS,CAAC;AAC1B;AACA,IAAI,EAAE,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AACtC,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC;AACnB,YAAY,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AACtE,YAAY,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC;AACnE,YAAY,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;AACrD,QAAQ,EAAE;AACV,IAAI,CAAC;AACL;AACA,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AAClF,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AAChF;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC3B,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE;AACnG,IAAI,CAAC;AACL;AACA,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACjC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;AACrC,IAAI,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,cAAc,CAAC;AAC9J,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;AAC1B,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE;AACvH,IAAI,CAAC;AACL;AACA,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;AACzF,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;AACzF,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE;AACzD,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS;AAClC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AACtC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AACtD,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;AAC9F,KAAK,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,EAAE;AAC/D,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM;AAC/B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AACtC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAChF,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC;AACnH,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAC/B,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AACtC,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7E;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ;AAClF,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC;AAC7D,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7B,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9B;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AAChC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AACtC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,EAAE;AACpE,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AACrC;AACA,IAAI,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC;AAClF,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC;AACxF,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC;AACzF,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AAC/B;AACA,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO;AACjJ,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AACzB,QAAQ,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,GAAG;AACvD,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;AAC3C,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;AAC5C,IAAI,CAAC;AACL;AACA,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG;AACzC,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG;AACzC,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE;AAC7C,IAAI,EAAE,iBAAiB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE;AAC3D;AACA,IAAI,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK;AAC1B,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AAC5C,IAAI,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;AAC9C,EAAE;AACF;AACA,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE;AAC5C,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACtB,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAClE,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,IAAI;AAC3F,QAAQ,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,EAAE;AACvE,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC7D,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,IAAI;AACjG,QAAQ,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,EAAE;AAClE,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACxC,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,IAAI;AACjG,QAAQ,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,EAAE;AAC7C,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC/B,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,IAAI;AACjG,QAAQ,IAAI,CAAC,MAAM,CAAC,aAAa,GAAG;AACpC,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AACrC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AAC9B,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;AAChD,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACrC,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,IAAI;AAC/F,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;AACtC,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;AACxD,YAAY,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;AACvD,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AACrC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;AACxB,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC5B,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,IAAI;AAC/F,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;AACtC,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;AACxD,YAAY,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,GAAG;AAC5D,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACzC,gBAAgB,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC;AACrC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,UAAU,CAAC;AAC1B,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC7B,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,EAAE;AAC5G,QAAQ,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,GAAG;AAC7C,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,cAAc,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAChC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,EAAE;AACxH,QAAQ,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,GAAG;AACtD,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACvB,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE;AACvG,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,GAAG;AACvC,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACxB,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE;AACnH,QAAQ,IAAI,CAAC,KAAK,GAAG;AACrB,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG;AACjC,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC;AACvD,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC3B,QAAQ,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;AAC9B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;AACvD,KAAK,EAAE;AACP,IAAI,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACzB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC;AAChG,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/B,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,QAAQ,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC,QAAQ,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;AAClC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;AAC7D,KAAK,EAAE;AACP,IAAI,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACvB,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG;AACnC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC/B,YAAY,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,GAAG;AAC3D,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE;AACtD,gBAAgB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,gBAAgB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;AACnD,gBAAgB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;AACpD,gBAAgB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACnD,oBAAoB,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,0BAA0B,GAAG;AAC7E,oBAAoB,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACjE,oBAAoB,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAClE,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,YAAY,IAAI,CAAC,MAAM,GAAG;AAC1B,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1C,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AAC9B,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE;AAClD,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE;AAC/E,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACxC,YAAY,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE;AACjE,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS;AACpE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;AAC1B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;AAC3F,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC;AAC1E,KAAK,EAAE;AACP,IAAI,yBAAyB,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AACpD,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,SAAS,CAAC,UAAU,GAAG,CAAC,IAAI,EAAE;AACzF,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,6BAA6B,CAAC,SAAS,CAAC,OAAO,GAAG,CAAC,IAAI,EAAE;AAC1F;AACA,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC1B,YAAY,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AAC5C,YAAY,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AAC5C,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AACzC,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB;AACxC,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;AAC5B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;AAC3D,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;AAC9F,KAAK,CAAC,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC;AAC5E,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3E,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;AACzF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ;AAC5F,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAC3E,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,GAAG;AACrE,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,cAAc,CAAC,EAAE,CAAC,QAAQ,GAAG;AACzF;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AAC7B,YAAY,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE;AACtD,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;AAC/B,YAAY,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE;AACvE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;AACzC,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACxC,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AACnC,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC1B,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7C,gBAAgB,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AACvE,gBAAgB,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,0BAA0B,GAAG;AACzE,gBAAgB,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAC7D,gBAAgB,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAC9D,gBAAgB,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;AAC1E;AACA,gBAAgB,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,YAAY;AAC7E,gBAAgB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE;AAC1E,gBAAgB,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;AAChF,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,oBAAoB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACpC,oBAAoB,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,kBAAkB,EAAE,CAAC,CAAC;AACpF,wBAAwB,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,4BAA4B,MAAM,CAAC;AACnC,wBAAwB,CAAC;AACzB,wBAAwB,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC,kBAAkB,EAAE;AAChF,wBAAwB,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,0BAA0B,GAAG;AACjF,wBAAwB,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACrE,wBAAwB,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACtE,oBAAoB,GAAG;AACvB,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,YAAY,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC;AACzC,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,OAAO,CAAC;AACvB,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACxC,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AAC9B,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,EAAE,IAAI,GAAG;AAC7C,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,cAAc,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC3C,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AAC9B,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG;AAChD,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AACxC,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AAC9B,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,EAAE;AACpD,QAAQ,OAAO,CAAC,SAAS,GAAG;AAC5B,QAAQ,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE;AAC9D,QAAQ,OAAO,CAAC,IAAI,GAAG;AACvB,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AACzD,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AAC9B,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,EAAE;AACpD,QAAQ,OAAO,CAAC,IAAI,GAAG;AACvB,QAAQ,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AACtC,QAAQ,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE;AAClE,QAAQ,OAAO,CAAC,OAAO,GAAG;AAC1B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;AACnD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO;AAC1C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;AAClE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AAC9E,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AAChC,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;AAChF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM;AAC5E,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK;AACtC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AACtE,KAAK,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE;AAC9D,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;AACzD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AAC1E,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG;AAC1E,KAAK,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,WAAW,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC;AAC1E,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;AAC9B,QAAQ,EAAE,CAAC,IAAI,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC;AACxC,YAAY,OAAO,CAAC,CAAC,CAAC,CAAC;AACvB,gBAAgB,OAAO,CAAC,CAAC,OAAO,CAAC;AACjC,gBAAgB,KAAK,CAAC,CAAC,KAAK,CAAC;AAC7B,gBAAgB,SAAS,CAAC,CAAC,SAAS,CAAC;AACrC,gBAAgB,kBAAkB,CAAC,CAAC,kBAAkB;AACtD,YAAY,EAAE;AACd,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AACpD,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT,QAAQ,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;AAClC,QAAQ,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC;AACxD,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACpC;AACA,QAAQ,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG;AAC5B,QAAQ,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC;AAC3C,QAAQ,EAAE,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC;AACjC,YAAY,IAAI,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC,CAAC,kBAAkB,CAAC;AACvE,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ;AAC1E,YAAY,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACnE,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC;AAC/F,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,gBAAgB,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AACzC,gBAAgB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAC9D,gBAAgB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC5D,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,gBAAgB,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1C,gBAAgB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AAChE,gBAAgB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC9D,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;AACnC,gBAAgB,IAAI,CAAC,YAAY,CAAC;AAClC,gBAAgB,MAAM,CAAC,CAAC,CAAC;AACzB,gBAAgB,MAAM,CAAC,CAAC,CAAC;AACzB,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,gBAAgB,MAAM,CAAC,MAAM,CAAC;AAC9B,gBAAgB,MAAM,CAAC,CAAC,CAAC;AACzB,gBAAgB,MAAM,CAAC,CAAC,CAAC;AACzB,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,gBAAgB,MAAM,CAAC,MAAM;AAC7B,YAAY,EAAE;AACd,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;AACvC,YAAY,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;AAC1C,YAAY,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC;AACzD,gBAAgB,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9C;AACA,YAAY,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,YAAY,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,YAAY,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAC5B,gBAAgB,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;AAC5E,gBAAgB,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;AAC/E,gBAAgB,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;AACrD,gBAAgB,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE;AACvD,YAAY,CAAC;AACb,YAAY,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;AACnC,gBAAgB,IAAI,CAAC,YAAY,CAAC;AAClC,gBAAgB,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAC9C,gBAAgB,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;AAC/C,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC3D,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7D,gBAAgB,CAAC,QAAQ,CAAC;AAC1B,gBAAgB,CAAC,SAAS,CAAC;AAC3B,gBAAgB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACjD,gBAAgB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;AAClD,YAAY,EAAE;AACd,QAAQ,CAAC;AACT,QAAQ,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG;AAC/B,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;AACzD,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAChC,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC;AACnG,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AACnC,QAAQ,OAAO,CAAC,IAAI,GAAG;AACvB,QAAQ,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AACpD,QAAQ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE;AACpF,QAAQ,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE;AAC9D,QAAQ,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE;AAC5D;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,YAAY,IAAI,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,GAAG;AACtE,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,YAAY,IAAI,CAAC,kBAAkB,EAAE;AACrC,gBAAgB,OAAO,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,EAAE;AACtD,gBAAgB,KAAK,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,sBAAsB,CAAC;AAClE,oBAAoB,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC;AAC7D,YAAY,GAAG;AACf,QAAQ,CAAC;AACT;AACA,QAAQ,OAAO,CAAC,UAAU,CAAC;AAC3B,YAAY,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AAClD,YAAY,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AAClD,YAAY,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AAC9C,YAAY,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB;AAC7C,QAAQ,EAAE;AACV;AACA,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AACtF,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AACtF;AACA,QAAQ,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;AAChD,QAAQ,OAAO,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,CAAC,WAAW,CAAC,EAAE;AACtD,QAAQ,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;AACjE,QAAQ,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE;AACxD;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AAC3C,YAAY,OAAO,CAAC,QAAQ,CAAC;AAC7B,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,GAAG;AACnD,gBAAgB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AACtD,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB;AAC5D,YAAY,EAAE;AACd,YAAY,OAAO,CAAC,QAAQ,CAAC;AAC7B,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,GAAG,QAAQ,GAAG;AAC/D,gBAAgB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AACtD,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB;AAC5D,YAAY,EAAE;AACd,QAAQ,CAAC;AACT,QAAQ,OAAO,CAAC,QAAQ,CAAC;AACzB,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;AACnC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AACzD,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB;AACxD,QAAQ,EAAE;AACV,QAAQ,OAAO,CAAC,QAAQ,CAAC;AACzB,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AACzD,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB;AACxD,QAAQ,EAAE;AACV,QAAQ,OAAO,CAAC,QAAQ,CAAC;AACzB,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7B,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AACzD,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB;AACxD,QAAQ,EAAE;AACV,QAAQ,OAAO,CAAC,QAAQ,CAAC;AACzB,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC3C,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AACzD,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB;AACxD,QAAQ,EAAE;AACV,QAAQ,OAAO,CAAC,QAAQ,CAAC;AACzB,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG;AAC5C,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AACzD,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB;AACxD,QAAQ,EAAE;AACV,QAAQ,OAAO,CAAC,QAAQ,CAAC;AACzB,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,GAAG;AACpD,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AACzD,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB;AACxD,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,YAAY,IAAI,CAAC,uBAAuB,GAAG;AAC3C,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,YAAY,IAAI,CAAC,uBAAuB,GAAG;AAC3C,QAAQ,CAAC;AACT,QAAQ,OAAO,CAAC,OAAO,GAAG;AAC1B,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/B,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC/B,YAAY,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AACvC,YAAY,OAAO,CAAC,IAAI,GAAG;AAC3B,YAAY,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AACxD,YAAY,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE;AACzD,YAAY,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE;AACvD;AACA,YAAY,OAAO,CAAC,UAAU,CAAC;AAC/B,gBAAgB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AAC7C,gBAAgB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AAC7C,gBAAgB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AACjD,gBAAgB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,iBAAiB;AACjD,YAAY,EAAE;AACd;AACA,YAAY,OAAO,CAAC,OAAO,GAAG;AAC9B,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI;AAC1B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM;AAClF,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AAC5D,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AACrC,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;AACrD,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE;AACxD,IAAI,EAAE;AACN;AACA,IAAI,eAAe,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACjC,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;AAC1E,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,kBAAkB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3C,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AACnC,YAAY,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,iBAAiB,CAAC,CAAC,CAAC;AACtD,YAAY,IAAI,CAAC,eAAe,GAAG;AACnC;AACA,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,SAAS,EAAE;AAC1D,QAAQ,OAAO,CAAC,IAAI,GAAG;AACvB;AACA,QAAQ,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AAC5C,QAAQ,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE;AACxD,QAAQ,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AAC9C,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,uBAAuB,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AAClD,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE;AAClD,QAAQ,OAAO,CAAC,OAAO,GAAG;AAC1B,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,oBAAoB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACtC,QAAQ,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;AACpD,QAAQ,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AAC5D,QAAQ,MAAM,CAAC,CAAC;AAChB,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC;AAClD,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,iBAAiB;AACjD,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,0BAA0B,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC5C,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,GAAG;AACrD,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,YAAY,MAAM,CAAC,UAAU,CAAC;AAC9B,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AAC9E,QAAQ,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC;AACrC,QAAQ,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACnD,YAAY,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACzC,YAAY,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG;AAC1C,QAAQ,MAAM,CAAC,CAAC;AAChB,YAAY,CAAC,CAAC,CAAC,gBAAgB,CAAC;AAChC,YAAY,CAAC,CAAC,CAAC,gBAAgB;AAC/B,QAAQ,EAAE;AACV,IAAI,CAAC;AACL,EAAE;AACF;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;ACppBpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ;AAC3B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ;AAClB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE;AAClF,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE;AACvC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;AACvD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAC5F,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACpG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAChG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACxG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACxG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACpG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACnG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAC/F,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACtG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAC9F,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAC9F,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACpF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACrG,CAAC,EAAE;AACH,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClC;AACA,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI;AACrE,IAAI,EAAE,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ;AAC9D,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACzB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AACpD,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC;AACnB,YAAY,aAAa,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE;AACpC,YAAY,WAAW,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE;AACpC,YAAY,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC;AACnC,QAAQ,EAAE;AACV,IAAI,CAAC;AACL;AACA,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU;AACnE,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ;AACpE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM;AACjD,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;AAC1B,QAAQ,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;AAClD,QAAQ,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9B,IAAI,CAAC;AACL;AACA,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE;AAC9B,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC;AAChB,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC;AACf,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC;AACjB,QAAQ,MAAM,CAAC,CAAC,CAAC;AACjB,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI;AAC9B;AACA,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;AAC3B;AACA,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3B;AACA,QAAQ,EAAE,QAAQ,CAAC,QAAQ;AAC3B,QAAQ,aAAa,CAAC,MAAM,IAAI,CAAC;AACjC,QAAQ,WAAW,CAAC,QAAQ,IAAI,CAAC;AACjC;AACA,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU;AACnC,QAAQ,SAAS,CAAC,UAAU,IAAI,CAAC;AACjC,QAAQ,MAAM,CAAC,WAAW,IAAI,CAAC;AAC/B;AACA,QAAQ,EAAE,YAAY,CAAC,OAAO;AAC9B,QAAQ,eAAe,CAAC,IAAI,EAAE,gBAAgB,CAAC,eAAe,CAAC;AAC/D,QAAQ,aAAa,CAAC,MAAM,EAAE,gBAAgB,CAAC,aAAa,CAAC;AAC7D,QAAQ,iBAAiB,CAAC,EAAE,EAAE,gBAAgB,CAAC,iBAAiB,CAAC;AACjE,QAAQ,iBAAiB,CAAC,EAAE,EAAE,gBAAgB,CAAC,iBAAiB,CAAC;AACjE,QAAQ,eAAe,CAAC,IAAI,EAAE,gBAAgB,CAAC,eAAe,CAAC;AAC/D,QAAQ,cAAc,CAAC,KAAK,EAAE,gBAAgB,CAAC,cAAc,CAAC;AAC9D,QAAQ,YAAY,CAAC,OAAO,EAAE,gBAAgB,CAAC,YAAY,CAAC;AAC5D,QAAQ,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,CAAC,gBAAgB,CAAC;AAChE,QAAQ,YAAY,CAAC,OAAO,EAAE,gBAAgB,CAAC,YAAY,CAAC;AAC5D,QAAQ,YAAY,CAAC,OAAO,EAAE,gBAAgB,CAAC,YAAY,CAAC;AAC5D,QAAQ,OAAO,CAAC,YAAY,EAAE,gBAAgB,CAAC,OAAO,CAAC;AACvD,QAAQ,eAAe,CAAC,IAAI,EAAE,gBAAgB,CAAC,eAAe;AAC9D;AACA,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE;AACjB;AACA,IAAI,IAAI,CAAC,yBAAyB,GAAG;AACrC;AACA,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE;AACvC,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC;AACnB,QAAQ,eAAe,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC;AAC9C,QAAQ,aAAa,CAAC,GAAG,IAAI,CAAC,aAAa;AAC3C,IAAI,GAAG;AACP,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE;AACvC,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC;AACnB,QAAQ,eAAe,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC;AAC9C,QAAQ,aAAa,CAAC,GAAG,IAAI,CAAC,aAAa;AAC3C,IAAI,GAAG;AACP,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE;AACvC,QAAQ,WAAW,CAAC,CAAC,IAAI,CAAC;AAC1B,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC;AACnB,QAAQ,eAAe,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC;AAC9C,QAAQ,aAAa,CAAC,GAAG,IAAI,CAAC,aAAa;AAC3C,IAAI,GAAG;AACP;AACA,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC;AACxD,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC;AACxD,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC;AACrD;AACA,IAAI,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;AACtD;AACA,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;AACtB,IAAI,IAAI,CAAC,MAAM,GAAG;AAClB,EAAE;AACF;AACA,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE;AAC9C,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACxB,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;AACrF,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK;AACtF,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC;AAClD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI;AACnD,KAAK,EAAE;AACP,IAAI,gBAAgB,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;AAC7C,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,QAAQ,GAAG;AAC7F,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,GAAG;AACnI,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG;AAChH,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG;AAChH;AACA,QAAQ,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE;AAClG,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;AACpD,QAAQ,EAAE,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,IAAI;AAChI,QAAQ,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE;AACtD,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM;AACxC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW;AAClF,IAAI,EAAE,CAAC,OAAO,CAAC,QAAQ;AACvB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI;AAC/E,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI;AACnD,IAAI,EAAE,CAAC,CAAC,OAAO;AACf,IAAI,iBAAiB,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;AACxD,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,GAAG;AACpF,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,GAAG;AACxH,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG;AAC/G,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG;AACjH;AACA,QAAQ,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,GAAG;AACrD,QAAQ,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,OAAO,GAAG,KAAK,CAAC;AAChF,YAAY,aAAa,EAAE;AAC3B;AACA,QAAQ,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG;AAC3E,QAAQ,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,GAAG,KAAK,CAAC,aAAa,EAAE;AAC/E,QAAQ,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AAC7E;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1B,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK;AAC7E,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACrE,aAAa,CAAC;AACd,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI;AAChC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AAC7C,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AAChH,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,WAAW;AAC1D,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AAC7E,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1E,aAAa,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC;AACpD,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa;AAC/C,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,aAAa,EAAE;AACf,YAAY,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AAClD,gBAAgB,WAAW,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,KAAK,GAAG;AAC/D,gBAAgB,aAAa,CAAC,CAAC,aAAa,CAAC;AAC7C,gBAAgB,UAAU,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,GAAG;AAChE,gBAAgB,aAAa,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE;AAC1D,YAAY,GAAG;AACf,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;AACtD,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE;AAC1D,KAAK,EAAE;AACP,IAAI,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC7B,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACpC,YAAY,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC;AACzC,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG;AAC5E,QAAQ,GAAG,CAAC,MAAM,CAAC;AACnB,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK;AACzE,YAAY,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;AAC1D,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;AAClD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACvD,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC;AAC5E,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC/B,QAAQ,MAAM,CAAC,IAAI,CAAC,qBAAqB,GAAG,MAAM,EAAE,IAAI,CAAC,WAAW,IAAI;AACxE,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACvD,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,GAAG;AACrD,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;AAC5E,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC;AAC5E,KAAK,EAAE;AACP,IAAI,qBAAqB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACvC,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,SAAS,GAAG;AACrD,QAAQ,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG;AAC9C,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG;AACnD;AACA,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC1B,YAAY,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACrC,YAAY,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACtC,YAAY,KAAK,CAAC;AAClB,YAAY,MAAM;AAClB,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW;AACnC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI;AAC7C,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;AACnC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1B,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,GAAG;AACnG,aAAa,CAAC;AACd,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;AAC1B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AAC7C,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AAChH,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW;AAC9C,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,aAAa,EAAE;AACf,YAAY,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;AAC5C,gBAAgB,WAAW,CAAC,CAAC,WAAW;AACxC,YAAY,GAAG;AACf,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,WAAW,EAAE;AACjE,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC5B,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG;AAC1C,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AACtC,YAAY,IAAI,CAAC,YAAY,CAAC,CAAC;AAC/B,gBAAgB,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClD;AACA,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC5B,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;AACrC,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AACpB,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;AAC7F,YAAY,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;AAC9C,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE;AACpD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,EAAE;AACP,IAAI,cAAc,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAChC,QAAQ,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;AACvE,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC;AACvF,KAAK,EAAE;AACP,IAAI,gBAAgB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAClC,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AAC3B,YAAY,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;AACjC,YAAY,IAAI,CAAC,aAAa,CAAC,CAAC;AAChC,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC;AACrF,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;AAC/F,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC5B,QAAQ,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ;AAC/F,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC;AACrF,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;AACvG,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACnC,QAAQ,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,GAAG;AAC1G;AACA,QAAQ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE;AAClC,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC;AACnB,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,QAAQ,EAAE,CAAC,OAAO,EAAE;AACpB;AACA,QAAQ,IAAI,CAAC,yBAAyB,GAAG;AACzC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1B,YAAY,IAAI,CAAC,MAAM,CAAC,WAAW,GAAG;AACtC,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACtE,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;AAC1G,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACpG,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAClC,QAAQ,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,WAAW,IAAI;AAC3E,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACtE,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,GAAG;AACrD,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;AACxE,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;AAC1G,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACpG,KAAK,EAAE;AACP,IAAI,iBAAiB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAC1C,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE;AAC7C,QAAQ,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;AACjD,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG;AACnD;AACA,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC1B,YAAY,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACrC,YAAY,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACtC,YAAY,KAAK,CAAC;AAClB,YAAY,MAAM;AAClB,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;AAC1G,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;AAC3E,KAAK,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACrE,KAAK,EAAE;AACP,IAAI,oBAAoB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAC7C,QAAQ,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,OAAO,EAAE,MAAM,CAAC;AACjE,YAAY,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,GAAG;AAC1D,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;AAC1G,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;AAC3E,KAAK,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACrE,KAAK,EAAE;AACP,IAAI,4BAA4B,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACrD,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE;AACrD,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;AACxE,QAAQ,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AAChD,QAAQ,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;AAC/C,QAAQ,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AAC5E,QAAQ,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AAC7E,QAAQ,MAAM,CAAC,MAAM,CAAC;AACtB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;AAC1G,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACpC,QAAQ,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AACxC,gBAAgB,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC;AACjD,gBAAgB,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK;AAChD,YAAY,EAAE;AACd,YAAY,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AACvC,gBAAgB,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC;AAChD,gBAAgB,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK;AAC/C,YAAY,EAAE;AACd,YAAY,YAAY,CAAC;AACzB,YAAY,IAAI,CAAC;AACjB,YAAY,KAAK,CAAC;AAClB,YAAY,MAAM,CAAC;AACnB,YAAY,MAAM,CAAC;AACnB,YAAY,YAAY,CAAC;AACzB,YAAY,eAAe,CAAC;AAC5B,YAAY,eAAe,CAAC;AAC5B;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACxB,YAAY,MAAM,CAAC,aAAa,CAAC;AACjC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACvC,YAAY,MAAM,CAAC,YAAY,CAAC;AAChC,QAAQ,CAAC;AACT;AACA,QAAQ,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE;AACjE;AACA,QAAQ,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG;AACjC,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7B,QAAQ,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG;AAChD,QAAQ,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC7B,YAAY,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1C,YAAY,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3C,YAAY,KAAK,CAAC;AAClB,YAAY,MAAM;AAClB,QAAQ,EAAE;AACV;AACA,QAAQ,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE;AACpE,QAAQ,eAAe,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,EAAE;AAC7D,QAAQ,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;AACtF;AACA,QAAQ,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,EAAE;AACpD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;AAC1G,KAAK,EAAE;AACP,IAAI,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClC,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACxB,YAAY,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC;AACjD,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC;AAChD,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,qBAAqB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3C,QAAQ,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;AACxB,YAAY,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI;AAC9C,YAAY,IAAI,CAAC,UAAU,IAAI;AAC/B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM;AACzC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC;AACvD,KAAK,EAAE;AACP,IAAI,yBAAyB,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AACjD,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AACnC,gBAAgB,MAAM,CAAC,CAAC,CAAC;AACzB,gBAAgB,MAAM,CAAC,CAAC,CAAC;AACzB,gBAAgB,MAAM,CAAC,KAAK,CAAC;AAC7B,gBAAgB,MAAM,CAAC,MAAM,EAAE;AAC/B;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;AAClC,YAAY,EAAE,EAAE,CAAC,OAAO;AACxB,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AAC7E,YAAY,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AAC5D,YAAY,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC;AACjG,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,mBAAmB,CAAC;AAC3F,YAAY,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC;AAC3E;AACA,YAAY,EAAE,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1E,gBAAgB,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtD,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,gBAAgB,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC;AACvC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,gBAAgB,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC;AACtC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AAChC,YAAY,EAAE,EAAE,CAAC,OAAO;AACxB,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,GAAG,CAAC,iBAAiB,GAAG,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC;AAC9E,YAAY,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC;AAC9D,YAAY,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC;AACnG,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,iBAAiB,CAAC;AACzF,YAAY,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC;AAC3E;AACA,YAAY,EAAE,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC;AACzE,gBAAgB,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtD,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtC,gBAAgB,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC;AACxC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,gBAAgB,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;AACrC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,SAAS,CAAC;AACzB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG;AAChG,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI;AACzC,KAAK,EAAE;AACP,IAAI,sBAAsB,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;AACnD,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1B,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,gBAAgB,GAAG;AACtH,aAAa,CAAC;AACd,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS;AAC/B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AAC7C,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AAChH,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG;AACnG,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI;AACjD,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,aAAa,EAAE;AACf,YAAY,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;AAClD,gBAAgB,WAAW,CAAC,CAAC,WAAW;AACxC,YAAY,GAAG;AACf,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,WAAW,CAAC,EAAE;AACvE,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;AACvE,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC;AAClD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS;AAClD,KAAK,EAAE;AACP,IAAI,gBAAgB,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;AAC7C,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG;AACxC,QAAQ,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,UAAU,EAAE;AACrE;AACA,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC;AAC7C,YAAY,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE;AACtE,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,GAAG;AAC9C,QAAQ,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,MAAM,EAAE;AACvE,QAAQ,IAAI,CAAC,sBAAsB,CAAC,WAAW,EAAE;AACjD;AACA,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE;AAC/C,YAAY,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE;AAC/C,YAAY,WAAW,CAAC,CAAC,CAAC;AAC1B,YAAY,IAAI,CAAC,SAAS,CAAC;AAC3B,gBAAgB,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,IAAI;AAC9D,gBAAgB,WAAW,EAAE;AAC7B,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,gBAAgB,CAAC;AACpE,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC;AAClD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS;AAClD,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;AAC1C,QAAQ,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE;AAClD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM;AACzC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC;AACrE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC;AAClD,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3C,QAAQ,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG;AAChC,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC;AACvD,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC;AACvD;AACA,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG;AAC3C,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,GAAG;AACxC;AACA,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC;AACpD,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AACnC,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,KAAK,CAAC;AACzB,YAAY,MAAM,CAAC,MAAM,CAAC;AAC1B,YAAY,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG;AAChD,YAAY,CAAC,cAAc,GAAG;AAC9B;AACA,QAAQ,EAAE,CAAC,CAAC,SAAS,CAAC,cAAc,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AACnD,YAAY,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AACxD,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;AACxD,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ;AACjE,QAAQ,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,QAAQ,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACtD,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AAC5C;AACA,QAAQ,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC1B,YAAY,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,SAAS,CAAC,cAAc,GAAG;AAClE,YAAY,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,OAAO,EAAE;AACzE;AACA,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC;AACjD,gBAAgB,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC;AAC7C,gBAAgB,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;AAChD,gBAAgB,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,gBAAgB,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC;AAC1E,gBAAgB,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D,YAAY,CAAC;AACb;AACA,YAAY,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,SAAS,EAAE;AAClE,YAAY,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,GAAG;AAC3C,YAAY,IAAI,CAAC,sBAAsB,CAAC,WAAW,EAAE;AACrD,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC1B,YAAY,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE;AACrC,YAAY,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE;AACpD,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;AAC/C,QAAQ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE;AACpD;AACA,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG;AACzC,QAAQ,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG;AACvC;AACA,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC5E,YAAY,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE;AACvC,YAAY,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE;AACnD,QAAQ,CAAC;AACT;AACA,QAAQ,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,IAAI;AAC1D,QAAQ,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC;AAClE,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,UAAU,GAAG,KAAK,CAAC,OAAO,EAAE;AACzD,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE;AACvC;AACA,QAAQ,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,CAAC,WAAW,EAAE;AACjE,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI;AACxE,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;AACjD,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG;AACtE,KAAK,CAAC,CAAC,eAAe,EAAE;AACxB,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,wBAAwB,CAAC,CAAC,EAAE,CAAC,OAAO;AAC7E,KAAK,CAAC,CAAC,IAAI,CAAC;AACZ,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM;AACzC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC;AAClD,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC9C,QAAQ,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AACxC,YAAY,WAAW,CAAC,CAAC,WAAW,CAAC;AACrC,YAAY,WAAW,CAAC,CAAC,KAAK;AAC9B,QAAQ,GAAG;AACX,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI;AACxE,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW;AAChF,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE;AAC9C,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG;AACtE,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC1D,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC;AACnE,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM;AACzC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC;AAClD,KAAK,EAAE;AACP,IAAI,wBAAwB,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC7D,QAAQ,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AACxC,YAAY,WAAW,CAAC,CAAC,WAAW,CAAC;AACrC,YAAY,WAAW,CAAC,CAAC,IAAI;AAC7B,QAAQ,GAAG;AACX,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC;AAC3D,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW;AACnC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC;AAClD,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;AAC1C,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC7B,YAAY,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;AACpE,YAAY,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;AAClC,YAAY,CAAC,CAAC;AACd,YAAY,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE;AACxC,QAAQ,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE;AAChD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC;AAC7D,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW;AACnC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC;AAClD,KAAK,EAAE;AACP,IAAI,eAAe,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;AAC5C,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC7B,YAAY,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;AAClC,YAAY,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;AACrE,YAAY,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;AACtC,YAAY,CAAC,EAAE;AACf,QAAQ,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE;AAChD,IAAI,EAAE;AACN;AACA;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO;AACrD,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO;AAC3C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;AAC1G,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC;AAClD,KAAK,EAAE;AACP,IAAI,oBAAoB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAC7C,QAAQ,GAAG,CAAC,MAAM,CAAC;AACnB,YAAY,iBAAiB,CAAC;AAC9B;AACA,QAAQ,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE;AACzC;AACA,QAAQ,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,MAAM,EAAE;AACnE;AACA,QAAQ,MAAM,CAAC,iBAAiB,CAAC;AACjC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW;AACnC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC;AAClD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG;AAC5C,KAAK,EAAE;AACP,IAAI,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC3C,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AACjC,YAAY,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC;AAC5C,YAAY,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK;AAC3C,QAAQ,EAAE;AACV,QAAQ,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE;AAC/D,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,MAAM;AAC1C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW;AACnC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC;AAClD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG;AAC5C,KAAK,EAAE;AACP,IAAI,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC5C,QAAQ,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC5B,YAAY,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACnD,YAAY,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACnD,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACpD,YAAY,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACpD,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;AAC1B,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,GAAG;AACtI,aAAa,CAAC;AACd,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG;AACzB,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AAC7C,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AAChH,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,MAAM;AACrD,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW;AAC9C,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,aAAa,EAAE;AACf,YAAY,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;AAC5C,gBAAgB,MAAM,CAAC,CAAC,MAAM,CAAC;AAC/B,gBAAgB,WAAW,CAAC,CAAC,WAAW;AACxC,YAAY,GAAG;AACf,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC;AAClD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI;AAC7C,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AACrD,QAAQ,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AAC3B,YAAY,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE;AAC1E,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK;AACxC,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;AACtD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AAC3E,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC;AAClD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI;AAC7C,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AACnD,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB;AACA,QAAQ,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,EAAE;AACvD,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACjC,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAChC,YAAY,QAAQ,CAAC,CAAC;AACtB,YAAY,IAAI,CAAC;AACjB;AACA,QAAQ,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC1B,YAAY,IAAI,CAAC,gCAAgC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC9D,gBAAgB,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE;AAC/C,YAAY,GAAG;AACf,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE;AAC3C,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1B,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,GAAG;AACjJ,aAAa,CAAC;AACd,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;AAC1B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AAC7C,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AAChH,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI;AACtC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ;AACvD,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW;AAC9C,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,aAAa,EAAE;AACf,YAAY,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;AAC5C,gBAAgB,IAAI,CAAC,CAAC,IAAI,CAAC;AAC3B,gBAAgB,QAAQ,CAAC,CAAC,QAAQ,CAAC;AACnC,gBAAgB,WAAW,CAAC,CAAC,WAAW;AACxC,YAAY,GAAG;AACf,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC;AAClD,KAAK,EAAE;AACP,IAAI,WAAW,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACpC,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC;AAC9D,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE;AACtD,QAAQ,IAAI,CAAC,iBAAiB,CAAC;AAC/B,YAAY,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,GAAG;AAC9C,YAAY,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,IAAI;AAClD,QAAQ,IAAI,CAAC,MAAM,CAAC,WAAW,GAAG;AAClC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;AACjD,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AACxB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;AACtF,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,OAAO,GAAG;AAC/D,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC;AAC5C,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC;AACxD,KAAK,EAAE;AACP,IAAI,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC7B,QAAQ,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;AAC5B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC;AAClD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM;AAC/C,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACpD,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,GAAG;AACjD,YAAY,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AAClC,YAAY,gBAAgB,CAAC;AAC7B;AACA,QAAQ,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAClD,QAAQ,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAClD;AACA,QAAQ,IAAI,CAAC,yBAAyB,GAAG;AACzC;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACzB,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ;AACpF,YAAY,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;AACzE,YAAY,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,gBAAgB,CAAC;AAClE,YAAY,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG;AACvE,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;AAC1B,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,GAAG;AAC7F,aAAa,CAAC;AACd,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAC5B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AAC7C,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AAChH,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,gBAAgB;AAC/D,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ;AAC3C,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,aAAa,EAAE;AACf,YAAY,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;AAC/C,gBAAgB,gBAAgB,CAAC,CAAC,gBAAgB,CAAC;AACnD,gBAAgB,QAAQ,CAAC,CAAC,QAAQ;AAClC,YAAY,GAAG;AACf,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE;AACjD,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,yBAAyB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC3C,QAAQ,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AAC/C,YAAY,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,GAAG;AAC3F,YAAY,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;AAC1F,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;AACpD,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;AAC5E,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACxB,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,QAAQ,IAAI,CAAC,gCAAgC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC1D,YAAY,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG;AACtC,QAAQ,GAAG;AACX;AACA,QAAQ,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG;AACpC,QAAQ,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG;AACpC;AACA,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AAC9E,YAAY,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AACpE,YAAY,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;AAC5D;AACA,QAAQ,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC;AAC5D,QAAQ,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC;AAC5D,QAAQ,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC;AACzD;AACA,QAAQ,MAAM,CAAC,OAAO,CAAC;AACvB,IAAI,EAAE;AACN;AACA,IAAI,gCAAgC,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC;AACnE,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AAC7B,YAAY,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE;AACzE,YAAY,iBAAiB,GAAG;AAChC,YAAY,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE;AACzE;AACA,YAAY,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,YAAY,EAAE;AACnE,YAAY,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC;AAC7D,gBAAgB,eAAe,CAAC,CAAC,IAAI,EAAE;AACvC;AACA,YAAY,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,EAAE;AAC1D,YAAY,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,EAAE;AAC1D;AACA,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,eAAe,GAAG,CAAC,CAAC;AACpD,gBAAgB,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AACtC,YAAY,CAAC;AACb,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,iBAAiB,GAAG;AAChC,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM;AAC/E,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;AACpE,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,qBAAqB,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;AAChF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC;AACpF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AAC7E,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;AAC3C,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,6BAA6B,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACnE,QAAQ,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC;AACjC,YAAY,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;AAC9D,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM;AAC/E,KAAK,CAAC,CAAC,WAAW,CAAC;AACnB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC;AACpF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AAC7E,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;AAC3C,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,qBAAqB,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3D,QAAQ,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC;AAClD,YAAY,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,IAAI;AACnD,YAAY,OAAO,EAAE;AACrB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,QAAQ;AAC/E,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;AACpE,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,qBAAqB,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;AAChF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC;AACpF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AAC7E,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;AAC3C,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,6BAA6B,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACnE,QAAQ,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC;AAClC,YAAY,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;AAC9D,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,QAAQ;AAC/E,KAAK,CAAC,CAAC,WAAW,CAAC;AACnB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC;AACpF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AAC7E,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;AAC3C,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,qBAAqB,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3D,QAAQ,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC;AACvE,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,IAAI;AACzC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC;AAC1D,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;AACvD,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;AACzE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW;AAClE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AAC7E,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;AAC3C,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,sBAAsB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACtD,QAAQ,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC;AAC5C,YAAY,KAAK,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,GAAG;AACpD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC;AACzD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW;AAClE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AAC7E,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;AAC3C,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,cAAc,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC9C,QAAQ,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,GAAG;AAC5E,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,uBAAuB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACtD,QAAQ,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3B,YAAY,MAAM,CAAC,UAAU,EAAE;AAC/B,QAAQ,EAAE,KAAK,CAAC;AAChB,YAAY,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK;AACrD,QAAQ,EAAE,IAAI,CAAC;AACf,YAAY,GAAG,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;AAC9D,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,eAAe,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC9C,QAAQ,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC;AAC5C,YAAY,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG;AACnE,YAAY,MAAM,EAAE;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACzD,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;AACvD,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;AACzE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW;AAC3D,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AAC7E,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;AAC3C,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,sBAAsB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACtD,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE;AACrD,QAAQ,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3B,YAAY,GAAG,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;AAC9D,QAAQ,EAAE,MAAM,CAAC;AACjB,YAAY,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK;AACrD,QAAQ,EAAE,IAAI,CAAC;AACf,YAAY,MAAM,CAAC,UAAU,EAAE;AAC/B,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACzD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW;AAC3D,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AAC7E,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;AAC3C,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,cAAc,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC9C,QAAQ,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC;AAClE,YAAY,CAAC,IAAI,CAAC,WAAW,GAAG;AAChC,YAAY,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;AAChC,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,qBAAqB,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACzD,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC;AACtD,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AAC3B,YAAY,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC1D,YAAY,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;AAC3D,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;AACzF,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE;AACxE,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK;AAC1B,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,0BAA0B,CAAC,OAAO,CAAC;AAC9F,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;AAC5E,KAAK,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;AAC5E,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AACvF,KAAK,EAAE;AACP,IAAI,0BAA0B,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC5D,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AACzC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU;AAClE,YAAY,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE;AACzE,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1B,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG;AACzD,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,gBAAgB,EAAE,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,0BAA0B,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC1F,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,0BAA0B,CAAC,OAAO,IAAI;AAC5F,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,gBAAgB,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,0BAA0B;AAC5E,gBAAgB,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AAC3E,gBAAgB,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;AACjC,gBAAgB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE;AAC1D,gBAAgB,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE;AAC/E,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC;AAC1C,YAAY,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC;AACpD,YAAY,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,EAAE;AACrD,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,qBAAqB,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACvD,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC;AACtD,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AAC3B,YAAY,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AACzD,YAAY,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;AAC1D,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM;AACxF,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE;AACxE,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK;AAC1B,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,0BAA0B,CAAC,OAAO,CAAC;AAC9F,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACtE,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;AAC/C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;AACxE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC1F,KAAK,EAAE;AACP,IAAI,0BAA0B,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1D,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AACxC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU;AAClE,YAAY,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AACvE,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1B,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG;AACzD,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,gBAAgB,EAAE,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,0BAA0B,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC1F,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,0BAA0B,CAAC,OAAO,IAAI;AAC5F,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,gBAAgB,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,0BAA0B;AAC5E,gBAAgB,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AAC3E,gBAAgB,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;AACjC,gBAAgB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE;AAC1D,gBAAgB,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE;AAC7E,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE;AAC/D,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC;AACjD,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC;AACjD,QAAQ,MAAM,CAAC,KAAK,CAAC;AACrB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AAC5E,KAAK,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,WAAW,CAAC;AACzE,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE;AACzE,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI;AACzB,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,wBAAwB,CAAC,OAAO,CAAC;AAC5F,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;AAC3E,KAAK,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;AACrF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS;AACxF,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;AAClC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;AACxE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;AAC1E,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW;AAChF,KAAK,EAAE;AACP,IAAI,wBAAwB,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AACjF,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AAC1B,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;AACxC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;AACtE,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE;AACvE,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1B,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG;AACzD,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,gBAAgB,EAAE,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,wBAAwB,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACxF,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,wBAAwB,CAAC,OAAO,IAAI;AAC1F,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,gBAAgB,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,wBAAwB;AAC1E,gBAAgB,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AAC3E,gBAAgB,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;AACjC,gBAAgB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE;AAC1D,gBAAgB,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC;AACrD,oBAAoB,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE;AACnE,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACrE,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE;AACzE,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC1B,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,IAAI,CAAC,OAAO;AACxB,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE;AAC/D,KAAK,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC;AACxE,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE;AACzE,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI;AACzB,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,wBAAwB,CAAC,OAAO,CAAC;AAC5F,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE;AAC3E,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ;AAC3E,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC;AACzB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS;AACzF,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;AACrC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;AAC7F,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;AAC/F,KAAK,EAAE;AACP,IAAI,wBAAwB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AACnF,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;AAC3B,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;AACxC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;AACtE,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE;AACzE,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1B,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG;AACzD,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,gBAAgB,EAAE,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,wBAAwB,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACxF,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,wBAAwB,CAAC,OAAO,IAAI;AAC1F,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,gBAAgB,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,0BAA0B;AAC5E,gBAAgB,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AAC3E,gBAAgB,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;AACjC,gBAAgB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE;AAC1D,gBAAgB,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC;AACrD,oBAAoB,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE;AACrE,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACrE,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE;AACzE,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC1B,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,IAAI,CAAC,OAAO;AACxB,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK;AACxE,KAAK,CAAC,CAAC,WAAW,CAAC;AACnB,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,+BAA+B,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxD,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE;AACvD,QAAQ,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC,KAAK,CAAC,EAAE;AACxD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AACzD,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;AAClC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,+BAA+B,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxD,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC,KAAK,CAAC,EAAE;AAC7D,QAAQ,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE;AAClD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC;AAC7E,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,wBAAwB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/C,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AACrC,YAAY,EAAE,QAAQ,CAAC,wBAAwB,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI;AACpF,QAAQ,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC5C,gBAAgB,EAAE,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG;AAC3D,QAAQ,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,iBAAiB,EAAE;AACvE,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AAC7E,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,wBAAwB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/C,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AACrC,YAAY,EAAE,QAAQ,CAAC,wBAAwB,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI;AACpF,QAAQ,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,+BAA+B,CAAC,KAAK,EAAE;AAC5E,QAAQ,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC;AACtC,gBAAgB,EAAE,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG;AAC3D,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ;AAC3E,KAAK,CAAC,CAAC,WAAW,CAAC;AACnB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,kCAAkC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3D,QAAQ,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE;AAClD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG;AACxE,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;AACtB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,kCAAkC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3D,QAAQ,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE;AAClD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO;AAC9E,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AAC/B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO;AACrE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS;AAC5D,KAAK,EAAE;AACP,IAAI,gCAAgC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AAC3D,QAAQ,MAAM,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC;AAClC,YAAY,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,UAAU,GAAG,CAAC,IAAI,EAAE;AAC9D,YAAY,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,WAAW,GAAG,CAAC,IAAI,EAAE;AAC/D,YAAY,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,aAAa,GAAG,CAAC,IAAI,CAAC;AAChE,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ;AAChF,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;AAC7B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO;AACrE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS;AAC5D,KAAK,EAAE;AACP,IAAI,gCAAgC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AAC3D,QAAQ,MAAM,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC;AAClC,YAAY,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,UAAU,GAAG,CAAC,IAAI,EAAE;AAC9D,YAAY,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,WAAW,GAAG,CAAC,IAAI,EAAE;AAC/D,YAAY,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,aAAa,GAAG,CAAC,IAAI,CAAC;AAChE,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AAChF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,2BAA2B,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAClD,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AACrC,YAAY,EAAE,QAAQ,CAAC,2BAA2B,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI;AACvF,QAAQ,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC5C,gBAAgB,EAAE,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG;AAC3D,QAAQ,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,iBAAiB,EAAE;AAC1E,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AAChF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,2BAA2B,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAClD,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AACrC,YAAY,EAAE,QAAQ,CAAC,2BAA2B,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI;AACvF,QAAQ,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,kCAAkC,CAAC,KAAK,EAAE;AAC/E,QAAQ,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC;AACtC,gBAAgB,EAAE,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG;AAC3D,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;AAChD,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC;AAC5E,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG;AACpD,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAC/E,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG;AACtF,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI;AACrD,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;AACnB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI;AACjD,KAAK,EAAE;AACP,IAAI,mBAAmB,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;AACjD,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1B,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG;AACzD,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,gBAAgB,EAAE,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC1E,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI;AAClD,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,gBAAgB,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,mBAAmB;AACrE,gBAAgB,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AAC3E,gBAAgB,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;AACjC,gBAAgB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE;AAC1D,gBAAgB,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,YAAY,EAAE;AAC9D,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC;AACrD,QAAQ,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;AACxD,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC;AACtD,QAAQ,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7E,QAAQ,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,wBAAwB,CAAC;AACvD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;AAChD,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC;AAC5E,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG;AACpD,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAC/E,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG;AACtF,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI;AAC/C,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;AACnB,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI;AACvD,KAAK,EAAE;AACP,IAAI,mBAAmB,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AAC9C,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1B,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG;AACzD,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,gBAAgB,EAAE,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACnF,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI;AACzC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,gBAAgB,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,mBAAmB;AACrE,gBAAgB,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AAC3E,gBAAgB,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;AACjC,gBAAgB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE;AAC1D,gBAAgB,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE;AAC3D,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC;AACrD,QAAQ,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;AACxD,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC;AACtD,QAAQ,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7E,QAAQ,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,wBAAwB,CAAC;AACpD,IAAI,CAAC;AACL,EAAE;AACF;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;ACn/CpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU;AAC7B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC;AAC5F,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC;AACzD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU;AACpB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,WAAW;AACrC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE;AAC7E,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;AACxD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC;AAC/D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;AAClG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;AACvF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC;AACjG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;AAC9F,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC;AACvG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AAC1E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACzE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACtE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACtE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW;AACrF,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;AAC3E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC;AAC/F,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC;AACrE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;AACpF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AAClF,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACjF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAChF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACnF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACjF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAC/E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAClF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAC3E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAC9E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAC/E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACxF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAC5E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AAC5G,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;AAC7G,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;AAC7K,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAC5E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAC5H,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAC3F,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACtF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC;AAC/C,CAAC,CAAC,MAAM,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;AACtD,CAAC,CAAC,MAAM,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACjE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,IAAI;AAC3C,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;AACnE,CAAC,EAAE;AACH,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACpC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACrB;AACA,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AACxF,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AAClF,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AAClF,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AAC5F,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AAClF,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC;AACrE,QAAQ,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,GAAG;AAC9E;AACA,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/B;AACA,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;AACxC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC;AAC7B;AACA,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AAClC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1B;AACA,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;AAC5C,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;AAC/B;AACA,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AACzC,QAAQ,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,GAAG;AAC1C,IAAI,CAAC;AACL;AACA,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;AACxB;AACA,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC3B,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;AACrB,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC3B,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;AACrB;AACA,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC;AAC/C,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AAChF,IAAI,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AACpF;AACA,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAClB,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC1B,QAAQ,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AAC9B,QAAQ,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;AAC7B;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC/B,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE;AACnG,YAAY,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;AAClC,QAAQ,CAAC;AACT,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAClC,QAAQ,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;AACjD,QAAQ,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9B,IAAI,CAAC;AACL;AACA,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;AACtC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC;AAC7B,IAAI,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC;AAC1F,IAAI,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC;AACtC;AACA,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AACvC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;AAC3B;AACA,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3B;AACA,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU;AACnC,QAAQ,MAAM,CAAC,SAAS,IAAI,CAAC;AAC7B,QAAQ,WAAW,CAAC,IAAI,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;AAC3E,QAAQ,QAAQ,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;AAChH,QAAQ,eAAe,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC;AACvI,QAAQ,SAAS,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;AAC9E,QAAQ,aAAa,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;AAC/E,QAAQ,QAAQ,CAAC,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;AACpF,QAAQ,UAAU,CAAC,KAAK,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC;AACxF,QAAQ,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC;AACzE,QAAQ,aAAa,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;AACtE,QAAQ,EAAE,YAAY,CAAC,QAAQ;AAC/B,QAAQ,eAAe,CAAC,QAAQ,EAAE,gBAAgB,CAAC,eAAe,CAAC;AACnE,QAAQ,aAAa,CAAC,UAAU,EAAE,gBAAgB,CAAC,aAAa,CAAC;AACjE,QAAQ,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,CAAC,iBAAiB,CAAC;AACrE,QAAQ,cAAc,CAAC,SAAS,EAAE,gBAAgB,CAAC,cAAc,CAAC;AAClE,QAAQ,YAAY,CAAC,WAAW,EAAE,gBAAgB,CAAC,YAAY,CAAC;AAChE,QAAQ,eAAe,CAAC,QAAQ,EAAE,gBAAgB,CAAC,eAAe,CAAC;AACnE,QAAQ,SAAS,CAAC,cAAc,EAAE,gBAAgB,CAAC,SAAS,CAAC;AAC7D,QAAQ,WAAW,CAAC,YAAY,EAAE,gBAAgB,CAAC,WAAW,CAAC;AAC/D,QAAQ,aAAa,CAAC,UAAU,EAAE,gBAAgB,CAAC,aAAa,CAAC;AACjE,QAAQ,sBAAsB,CAAC,CAAC,EAAE,gBAAgB,CAAC,sBAAsB,CAAC;AAC1E,QAAQ,SAAS,CAAC,cAAc,EAAE,gBAAgB,CAAC,SAAS,CAAC;AAC7D,QAAQ,SAAS,CAAC,cAAc,EAAE,gBAAgB,CAAC,SAAS,CAAC;AAC7D,QAAQ,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,CAAC,iBAAiB,CAAC;AACrE,QAAQ,mBAAmB,CAAC,IAAI,EAAE,gBAAgB,CAAC,mBAAmB,CAAC;AACvE,QAAQ,oBAAoB,CAAC,GAAG,EAAE,gBAAgB,CAAC,oBAAoB,CAAC;AACxE,QAAQ,OAAO,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,OAAO,CAAC;AAC3D,QAAQ,OAAO,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,OAAO,CAAC;AAC3D,QAAQ,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,CAAC,kBAAkB;AACrE,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE;AACjB;AACA,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AACjC,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;AACxB;AACA,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC;AAC9B;AACA,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE;AAClC,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC;AACnB,QAAQ,eAAe,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC;AAC9C,QAAQ,aAAa,CAAC,CAAC,IAAI,CAAC,aAAa;AACzC,IAAI,GAAG;AACP;AACA,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE;AAClC,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC;AACnB,QAAQ,eAAe,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC;AAC9C,QAAQ,aAAa,CAAC,CAAC,IAAI,CAAC,aAAa;AACzC,IAAI,GAAG;AACP;AACA,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE;AACtC,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC;AACvB,QAAQ,eAAe,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC;AAC9C,QAAQ,aAAa,CAAC,CAAC,IAAI,CAAC,aAAa;AACzC,IAAI,GAAG;AACP;AACA,IAAI,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE;AACxC,QAAQ,OAAO,CAAC,CAAC,OAAO,CAAC;AACzB,QAAQ,eAAe,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC;AAC9C,QAAQ,aAAa,CAAC,CAAC,IAAI,CAAC,aAAa;AACzC,IAAI,GAAG;AACP;AACA,IAAI,IAAI,CAAC,eAAe,GAAG;AAC3B;AACA,IAAI,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AACpB,QAAQ,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,kBAAkB,CAAC,CAAC,IAAI,EAAE;AAC5D,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM;AACvE,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3C,MAAM,GAAG;AACT,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;AAC9G,OAAO,CAAC;AACR,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE;AAClF,OAAO,CAAC;AACR,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO;AAC5B,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACvC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACvB,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACzG,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;AACpE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3F,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;AAC3F,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;AACvG,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC5E,OAAO,EAAE;AACT,QAAQ,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE;AAC1D,YAAY,UAAU,CAAC,CAAC,KAAK;AAC7B,QAAQ,EAAE,CAAC,IAAI,GAAG;AAClB,IAAI,EAAE;AACN,EAAE;AACF;AACA,EAAE,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG;AAC3G,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;AACnE,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC3B,QAAQ,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;AAC/B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AACvH,KAAK,EAAE;AACP,IAAI,cAAc,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAChC,QAAQ,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC;AACjC,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,eAAe,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AACrC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AACzC,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU;AAC3G,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AACjE,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM;AACrC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU;AAC7C,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;AAC1E,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACnH,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAChD,YAAY,WAAW,CAAC,CAAC,IAAI,CAAC,YAAY;AAC1C,QAAQ,GAAG;AACX,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AAClE,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,MAAM,EAAE;AAC/C,KAAK,EAAE;AACP,IAAI,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACvB,QAAQ,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,IAAI,EAAE;AAC5C,QAAQ,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AACrC,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC;AAC5D,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC;AAC1D,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACxB,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG;AAC9C,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG;AAC9C,QAAQ,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG;AACtD,QAAQ,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG;AAC1D;AACA,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC;AACrE,YAAY,IAAI,CAAC,eAAe,GAAG;AACnC,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACnC,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,KAAK,CAAC;AACrB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AAC1C,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACtB,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AAClD,YAAY,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC,YAAY,IAAI,CAAC,eAAe,GAAG;AACnC,YAAY,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAClC,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE;AAC5D,KAAK,EAAE;AACP,IAAI,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACzB,QAAQ,IAAI,CAAC,KAAK,GAAG;AACrB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AAC5D,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AAC7E,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;AACjC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACtF,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAClC,QAAQ,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC;AAC9C,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,GAAG;AAChF,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM;AAC1E,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;AAC7B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AAC7E,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;AACjC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACtF,KAAK,EAAE;AACP,IAAI,iBAAiB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAC1C,QAAQ,MAAM,CAAC,OAAO,CAAC,CAAC;AACxB,YAAY,GAAG,CAAC,EAAE,IAAI,CAAC;AACvB,gBAAgB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;AAC5C,gBAAgB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;AAC5C,gBAAgB,IAAI,CAAC,kBAAkB,CAAC;AACxC,gBAAgB,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;AAC3C,YAAY,GAAG,CAAC,EAAE,IAAI,CAAC;AACvB,gBAAgB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC;AAC3C,gBAAgB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC;AAC3C,gBAAgB,IAAI,CAAC,iBAAiB,CAAC;AACvC,gBAAgB,IAAI,CAAC,kBAAkB,EAAE;AACzC,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,UAAU;AACjB,IAAI,cAAc,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAChC,QAAQ,EAAE,OAAO,CAAC,KAAK,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,OAAO,GAAG;AACvG,QAAQ,MAAM,CAAC,IAAI,CAAC,SAAS,GAAG;AAChC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;AAC/D,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AAC3E,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;AACrC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACpE,KAAK,EAAE;AACP,IAAI,gBAAgB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACzC,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE;AACrD,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACzB,YAAY,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;AACtC,gBAAgB,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC;AACjE,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AAC9D,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE;AAC/C,YAAY,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAChC,gBAAgB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAClC,gBAAgB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAClC,gBAAgB,IAAI,CAAC,KAAK,CAAC;AAC3B,gBAAgB,IAAI,CAAC,MAAM,EAAE;AAC7B,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,GAAG;AACzF,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;AACzF,KAAK,EAAE;AACP,IAAI,cAAc,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAChC,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE;AAC/E,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,qBAAqB,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClE,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE;AACjG,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;AACxE,YAAY,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG;AAClF,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;AACzF,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE;AACrG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;AAC7G,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;AAClF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;AAC3G,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AACvF,KAAK,EAAE;AACP,IAAI,0BAA0B,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACrE,QAAQ,GAAG,CAAC,KAAK,CAAC;AAClB,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AACzC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU;AAClE,YAAY,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;AAC9B,YAAY,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;AAC5B,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE;AAClD,QAAQ,CAAC;AACT;AACA,QAAQ,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,GAAG;AAC1F,QAAQ,MAAM,CAAC,OAAO,CAAC,CAAC;AACxB,YAAY,IAAI,CAAC,qBAAqB,CAAC;AACvC,gBAAgB,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;AACtD,gBAAgB,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;AACxD,YAAY,IAAI,CAAC,qBAAqB,CAAC;AACvC,gBAAgB,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC;AACrD,gBAAgB,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE;AACtD,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,qBAAqB,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAChE,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE;AACjG,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AACvE,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;AAC/E,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM;AACxF,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE;AACrG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;AACzG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;AAC9E,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;AAC3G,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC1F,KAAK,EAAE;AACP,IAAI,0BAA0B,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACnE,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AACxC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU;AAClE,YAAY,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;AAC7B,YAAY,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC9B,YAAY,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC9B,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE;AAC/D,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACtB,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;AACnD,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;AACnD,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC;AAClD,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC;AAClD,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,GAAG;AACxF,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AAC5E,KAAK,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,WAAW,CAAC;AACzE,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE;AACrG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;AAC/G,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;AAChF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;AAC1E,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;AAC5E,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;AAC3G,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;AACxF,KAAK,EAAE;AACP,IAAI,wBAAwB,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC1F,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AAC1B,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AACrC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU;AACjE,YAAY,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;AAC7B,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE;AACvE,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,OAAO,EAAE;AACjF,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE;AAClF;AACA,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC1B,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;AACpD,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE;AAC/D,KAAK,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC;AACxE,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE;AACrG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;AACnH,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;AACpF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;AAC9E,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;AAChF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;AAC3G,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AACrF,KAAK,EAAE;AACP,IAAI,wBAAwB,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC9F,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;AAC3B,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AACxC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU;AACjE,YAAY,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;AAC9B,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE;AACzE,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,OAAO,EAAE;AACjF,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE;AAClF;AACA,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC1B,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,MAAM,CAAC,CAAC,CAAC;AACrB,YAAY,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;AACpD,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK;AACxE,KAAK,CAAC,CAAC,WAAW,CAAC;AACnB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,+BAA+B,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxD,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE;AAChE,QAAQ,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC,KAAK,CAAC,EAAE;AACxD,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AACzD,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;AAClC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,+BAA+B,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxD,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC,KAAK,CAAC,EAAE;AAC7D,QAAQ,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE;AAC3D,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC;AAC7E,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,wBAAwB,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACjD,QAAQ,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAC5C,gBAAgB,aAAa,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG;AACzE,QAAQ,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC,iBAAiB,CAAC,EAAE;AACzE,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AAC7E,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,wBAAwB,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACjD,QAAQ,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC,KAAK,CAAC,EAAE;AAC9E,QAAQ,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC;AACtC,gBAAgB,aAAa,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG;AACzE,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK;AAC1E,IAAI,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;AAC1D,IAAI,8BAA8B,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AACpD,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC;AACpD,QAAQ,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,GAAG;AAClF,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC1B,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC3D,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC3D,YAAY,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AAC/B,YAAY,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;AAChC,YAAY,IAAI,CAAC,OAAO,EAAE;AAC1B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;AAChD,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC;AAC5E,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG;AACpD,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAC/E,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG;AACtF,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI;AACrD,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI;AACjD,KAAK,EAAE;AACP,IAAI,mBAAmB,CAAC,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACnD,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AACrD,gBAAgB,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AAC/E,QAAQ,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC;AACpC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;AAChD,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC;AAC5E,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG;AACpD,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAC/E,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG;AACtF,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,QAAQ;AAChB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI;AAC/C,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI;AACvD,KAAK,EAAE;AACP,IAAI,mBAAmB,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAChD,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AACrD,gBAAgB,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AAC/E,QAAQ,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;AACjC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AACnD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACzF,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC;AACzG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM;AAC1D,KAAK,EAAE;AACP,IAAI,WAAW,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAClD,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;AACtE,YAAY,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE;AACvD;AACA,QAAQ,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC1B,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;AAC3E,oBAAoB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,gBAAgB,MAAM,CAAC;AACvB,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE;AAC9C,YAAY,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE;AAC9C,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACnC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;AAC7B,gBAAgB,MAAM,CAAC;AACvB,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE;AAC/C,YAAY,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE;AAC/C,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACnC,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;AAC1B,YAAY,IAAI,CAAC,kBAAkB,GAAG;AACtC,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC;AACrG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACtE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC;AACrG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM;AAC1D,KAAK,EAAE;AACP,IAAI,QAAQ,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC5C,QAAQ,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE;AAC3C,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC;AACrG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AACxE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC;AACrG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM;AAC1D,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC9C,QAAQ,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE;AAC9D,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC;AAC1E,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM;AAC3E,KAAK,CAAC,CAAC,KAAK;AACZ,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;AAC3E,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC;AAC/E,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AAC7C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI;AAC9E,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC;AAC3B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM;AAC1D,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AACtD,QAAQ,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC;AAC9C,QAAQ,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,MAAM,EAAE;AAC9D,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC;AAC9C,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AACxB,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AACxB,QAAQ,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,QAAQ,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACzB,YAAY,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG;AACtD,YAAY,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AAC9E,YAAY,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AAChF,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AACxD,gBAAgB,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;AAC3E,gBAAgB,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;AAC3E,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;AACzE,gBAAgB,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;AACzE,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AACpD,YAAY,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI;AACjD,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,oBAAoB,CAAC;AAC9D,YAAY,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,YAAY,EAAE,CAAC,CAAC,gBAAgB,CAAC,sBAAsB,CAAC,CAAC,CAAC;AAC1D,gBAAgB,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9E,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;AAClD,gBAAgB,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC;AACxE,YAAY,CAAC;AACb,YAAY,IAAI,CAAC,WAAW,CAAC;AAC7B,gBAAgB,GAAG,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE;AACjF,gBAAgB,WAAW,EAAE;AAC7B,YAAY,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE;AAChD,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI;AACjD,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,mBAAmB,CAAC;AAC3D,YAAY,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,YAAY,EAAE,CAAC,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,CAAC,CAAC;AACxD,gBAAgB,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7E,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;AACnD,gBAAgB,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC;AACvE,YAAY,CAAC;AACb,YAAY,IAAI,CAAC,WAAW,CAAC;AAC7B,gBAAgB,GAAG,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE;AAChF,gBAAgB,WAAW,EAAE;AAC7B,YAAY,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE;AAC9C,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC;AAClF,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;AACxC,KAAK,EAAE;AACP,IAAI,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACzB,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACzB,YAAY,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG;AACtC,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;AACtF,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AACtF,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;AAC9C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM;AACxD,KAAK,EAAE;AACP,IAAI,OAAO,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAChC,QAAQ,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC;AAC/D,YAAY,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,GAAG;AAClF;AACA,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AACxC,YAAY,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,GAAG;AACzC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9B,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;AACxD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM;AAC7B,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU;AAC7C,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG;AAChF,SAAS,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7C,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,GAAG;AACvC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1D,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC5B,QAAQ,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;AAC5B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;AAC1E,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM;AAC3D,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACnC,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AACvC,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;AAC/B,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC;AAC3D,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM;AAChC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU;AAC7C,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;AAC9D,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG;AAChF,SAAS,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7C,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AAC3C,YAAY,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO;AACjC,QAAQ,GAAG;AACX,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;AAClG,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC5B,QAAQ,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;AAC7B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;AACjF,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACnC,QAAQ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC;AAClC,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC;AACvD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;AACpF,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC;AACrE,KAAK,EAAE;AACP,IAAI,WAAW,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACpC,QAAQ,MAAM,CAAC,OAAO,CAAC,CAAC;AACxB,YAAY,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC/C,YAAY,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC;AAC7C,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC;AAC/D,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC;AACvD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK;AAC/E,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC;AAC7B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM;AAC1D,KAAK,EAAE;AACP,IAAI,WAAW,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AACjD,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;AAC3D,YAAY,IAAI,CAAC,cAAc,CAAC,eAAe,GAAG,CAAC,CAAC;AACpD,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC1B,YAAY,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,OAAO,EAAE;AACjD,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,OAAO,EAAE;AAClD,QAAQ,CAAC;AACT,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B,QAAQ,IAAI,CAAC,kBAAkB,GAAG;AAClC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO;AAC7D,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;AAClF,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,iBAAiB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAC1C,QAAQ,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,SAAS,GAAG;AAC3D,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC;AACrE,KAAK,EAAE;AACP,IAAI,qBAAqB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACvC,QAAQ,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC;AACvC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC;AAC7G,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM;AACvE,KAAK,EAAE;AACP,IAAI,qBAAqB,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC;AACzD,QAAQ,EAAE,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC;AAC7D,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,kBAAkB,CAAC;AACrD,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC;AAC3D,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM;AAC5C,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU;AAC7C,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC,KAAK,CAAC;AACpF,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG;AAChF,SAAS,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7C,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;AACvD,YAAY,kBAAkB,CAAC,CAAC,IAAI,CAAC,kBAAkB;AACvD,QAAQ,GAAG;AACX,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC7C,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE;AACpE,QAAQ,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC1B,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1E,gBAAgB,MAAM,CAAC;AACvB,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE;AAC7C,YAAY,IAAI,CAAC,eAAe,GAAG;AACnC,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACnC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;AAC7B,gBAAgB,MAAM,CAAC;AACvB,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,EAAE;AAC9C,YAAY,IAAI,CAAC,eAAe,GAAG;AACnC,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACnC,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;AAC1B,YAAY,IAAI,CAAC,kBAAkB,GAAG;AACtC,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,eAAe,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACjC,QAAQ,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC;AAChE,QAAQ,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC;AACnF,QAAQ,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC;AAClE,QAAQ,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC;AACrF,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,kBAAkB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACpC,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;AAC3D,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC;AACvF,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC;AAC5C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM;AAC/B,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU;AAC7C,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG;AAChF,SAAS,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7C,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,GAAG;AACzC,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC/B,QAAQ,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;AACvD,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,kBAAkB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACpC,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AACnC,YAAY,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;AACjC,YAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE;AACtE,QAAQ,EAAE;AACV,QAAQ,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,6BAA6B,CAAC;AAC3E,YAAY,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AACnD,YAAY,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC;AAC5C,QAAQ,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AACpC,YAAY,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;AAC3C,YAAY,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;AAChC,gBAAgB,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7E,YAAY,EAAE;AACd,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI;AAC1D,QAAQ,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS;AACnE,QAAQ,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,YAAY,EAAE;AAC1D,QAAQ,MAAM,CAAC,CAAC;AAChB,YAAY,WAAW,CAAC,CAAC,WAAW,CAAC;AACrC,YAAY,YAAY,CAAC,CAAC,YAAY;AACtC,QAAQ,EAAE;AACV,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO;AACf,KAAK,CAAC,CAAC,CAAC,KAAK;AACb,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK;AAChF,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;AACjF,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;AACzD,KAAK,EAAE;AACP,IAAI,eAAe,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACjC,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC;AAChC,QAAQ,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,QAAQ,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG;AAClC;AACA,QAAQ,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK;AAC5C,QAAQ,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3C,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,GAAG;AAC5C,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC;AACpC,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;AACrC,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,8BAA8B,CAAC;AAC3D,YAAY,QAAQ,CAAC,oBAAoB,CAAC,IAAI,GAAG;AACjD;AACA,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AACzD,YAAY,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,8BAA8B,CAAC;AACvE,gBAAgB,IAAI,CAAC,gBAAgB,CAAC,IAAI,GAAG;AAC7C,YAAY,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,gBAAgB,EAAE;AAC/D,YAAY,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACpC,gBAAgB,MAAM,CAAC;AACvB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,GAAG;AACvD,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,WAAW,CAAC;AACrD,QAAQ,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,cAAc,CAAC,YAAY,CAAC;AACvD,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5B,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;AAC9B,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG;AAClC;AACA,QAAQ,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK;AAC9C,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;AACvE,YAAY,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;AAClC;AACA,YAAY,EAAE,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI;AACvE,YAAY,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC;AACjF,gBAAgB,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE;AACjD,gBAAgB,IAAI;AACpB,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC;AAClD;AACA,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE;AACxC,gBAAgB,EAAE,SAAS,CAAC,EAAE,CAAC,uBAAuB,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;AAChF,gBAAgB,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC,gBAAgB,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;AACpC,gBAAgB,QAAQ,CAAC;AACzB,YAAY,CAAC;AACb;AACA,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;AACpE,YAAY,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC;AAChF,gBAAgB,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE;AACjD,gBAAgB,KAAK;AACrB,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC;AAClD;AACA,YAAY,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC;AACzE,gBAAgB,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;AAC1C,oBAAoB,IAAI,CAAC,GAAG,CAAC;AAC7B,wBAAwB,IAAI,CAAC,MAAM,CAAC,eAAe,GAAG;AACtD,wBAAwB,CAAC;AACzB,oBAAoB,CAAC;AACrB,gBAAgB,EAAE;AAClB,gBAAgB,KAAK;AACrB,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC;AAClD;AACA,YAAY,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC;AAC1E,YAAY,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAClF,YAAY,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AAC1D,gBAAgB,YAAY,CAAC,CAAC,CAAC,sBAAsB;AACrD,YAAY,EAAE;AACd;AACA,YAAY,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI;AACrE,YAAY,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC;AACnC,gBAAgB,IAAI,CAAC;AACrB,gBAAgB,SAAS,CAAC;AAC1B,gBAAgB,SAAS,CAAC;AAC1B,gBAAgB,KAAK,CAAC;AACtB,gBAAgB,YAAY,CAAC;AAC7B,gBAAgB,eAAe,CAAC;AAChC,gBAAgB,QAAQ,CAAC;AACzB,gBAAgB,WAAW,CAAC;AAC5B,gBAAgB,QAAQ;AACxB,YAAY,EAAE;AACd;AACA,YAAY,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE;AACvE,YAAY,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK;AAClC,YAAY,EAAE,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;AACzD,gBAAgB,KAAK,CAAC;AACtB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO;AACrC,QAAQ,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE;AACxC;AACA,QAAQ,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI;AACnC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AAC9C,YAAY,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE;AAClD,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACnC,YAAY,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE;AACxC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,EAAE;AAC3D,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,eAAe,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACtE,QAAQ,GAAG,CAAC,KAAK,CAAC;AAClB,QAAQ,GAAG,CAAC,MAAM,CAAC;AACnB,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;AAClC,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACxD,YAAY,MAAM,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC7D,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE;AAChD,YAAY,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,EAAE;AACrD,QAAQ,CAAC;AACT,QAAQ,GAAG,CAAC,IAAI,CAAC;AACjB,QAAQ,GAAG,CAAC,OAAO,CAAC;AACpB,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;AACtD,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AAChC,YAAY,IAAI,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;AACjE,YAAY,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;AACxE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE;AAC/C,YAAY,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,gBAAgB,CAAC,CAAC,EAAE;AAChE,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG;AACtF,QAAQ,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,GAAG;AAC9F,QAAQ,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE;AACvD;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;AAClC,YAAY,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE;AACrE,YAAY,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,EAAE;AAC7E,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AAChC,YAAY,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;AACnF,YAAY,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;AAC3F,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,CAAC;AAChB,YAAY,OAAO,CAAC,CAAC,WAAW,CAAC;AACjC,YAAY,WAAW,CAAC,CAAC,eAAe,CAAC;AACzC,QAAQ,EAAE;AACV,IAAI,CAAC;AACL,GAAG;AACH;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;AACjD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC;AAClF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS;AAC7B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS;AAC7B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AACxB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY;AAC/B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe;AAClC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;AACzF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;AAC7F,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AAC9B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;AACtE,CAAC,EAAE;AACH,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC;AAC3E,IAAI,eAAe,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACnD;AACA,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,GAAG,UAAU,GAAG;AAC9D,IAAI,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,GAAG,cAAc,GAAG;AACtE;AACA,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AAC5B,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC;AAC3C,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK;AAC9B,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC;AAC7F,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS;AACvC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO;AACrC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU;AACxC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,QAAQ;AAClD,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO;AACtE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO;AAC1E,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AACzC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI;AAClC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,UAAU,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;AACtD,YAAY,UAAU,CAAC,CAAC,UAAU,CAAC;AACnC,YAAY,SAAS,CAAC,CAAC,SAAS,CAAC;AACjC,YAAY,KAAK,CAAC,CAAC,KAAK,CAAC;AACzB,YAAY,OAAO,CAAC,CAAC,YAAY,CAAC;AAClC,YAAY,UAAU,CAAC,CAAC,eAAe,CAAC;AACxC,YAAY,QAAQ,CAAC,CAAC,QAAQ,CAAC;AAC/B,YAAY,OAAO,CAAC,CAAC,YAAY,CAAC;AAClC,YAAY,WAAW,CAAC,CAAC,gBAAgB,CAAC;AAC1C,YAAY,WAAW,CAAC,CAAC,WAAW,CAAC;AACrC,YAAY,IAAI,CAAC,CAAC,IAAI;AACtB,QAAQ,GAAG;AACX,IAAI,CAAC;AACL;AACA,IAAI,aAAa,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE;AAC9C,IAAI,aAAa,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,KAAK,EAAE;AACrD;AACA,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY;AAC/C,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,gBAAgB,EAAE;AACxF,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC;AAC1C,IAAI,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,WAAW,CAAC,WAAW,CAAC;AAClD,IAAI,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE;AAC9D;AACA,IAAI,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,cAAc,CAAC;AAC5D,QAAQ,UAAU,CAAC,QAAQ,CAAC,SAAS,IAAI;AACzC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC9D,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAClE;AACA,YAAY,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG;AACjF,YAAY,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AACzE,YAAY,EAAE,CAAC,EAAE,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC;AACzE,gBAAgB,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9E,gBAAgB,EAAE,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACjE,oBAAoB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;AAC/E,oBAAoB,QAAQ,CAAC;AAC7B,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC;AAC9B,gBAAgB,UAAU,CAAC;AAC3B,gBAAgB,SAAS,CAAC;AAC1B,gBAAgB,SAAS,CAAC;AAC1B,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;AACrB,gBAAgB,KAAK,CAAC;AACtB,gBAAgB,YAAY,CAAC;AAC7B,gBAAgB,eAAe,CAAC;AAChC,gBAAgB,cAAc,CAAC;AAC/B,gBAAgB,aAAa,CAAC;AAC9B,gBAAgB,WAAW,CAAC;AAC5B,gBAAgB,IAAI;AACpB,YAAY,EAAE;AACd;AACA,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,MAAM,CAAC,IAAI,CAAC;AAChB,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC;AACzD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC;AAClF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS;AAC7B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS;AAC7B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AACxB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY;AAC/B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe;AAClC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,cAAc;AAC9C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa;AAChC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AAC9B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;AACtE,CAAC,EAAE;AACH,QAAQ,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,eAAe,CAAC,CAAC,cAAc,CAAC,CAAC,aAAa,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE;AACrJ;AACA,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;AACvB,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AACjB,YAAY,KAAK,CAAC;AAClB,YAAY,UAAU,CAAC;AACvB,YAAY,UAAU,CAAC,MAAM,CAAC;AAC9B,YAAY,UAAU,CAAC,WAAW,CAAC;AACnC,YAAY,WAAW,CAAC;AACxB,YAAY,aAAa,CAAC;AAC1B,YAAY,UAAU,CAAC,kBAAkB,CAAC;AAC1C,YAAY,UAAU,CAAC,mBAAmB;AAC1C,QAAQ,EAAE;AACV,QAAQ,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7B;AACA,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;AAC5B,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC;AAC3C,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI;AAC7B,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC;AAC7F,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI;AAC9C,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;AACtD,YAAY,UAAU,CAAC,CAAC,UAAU,CAAC;AACnC,YAAY,IAAI,CAAC,CAAC,IAAI;AACtB,QAAQ,GAAG;AACX,IAAI,CAAC;AACL;AACA,IAAI,WAAW,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3D;AACA,IAAI,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC5G,IAAI,WAAW,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,EAAE;AAC1E;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACzB,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACnC,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D,YAAY,WAAW,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;AAClE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5B,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACtB,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,CAAC;AACL;AACA,IAAI,YAAY,CAAC;AACjB,QAAQ,IAAI,CAAC;AACb,QAAQ,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC;AACtC,QAAQ,UAAU,CAAC,QAAQ,CAAC;AAC5B,QAAQ,cAAc,CAAC;AACvB,QAAQ,eAAe,CAAC;AACxB,QAAQ,UAAU;AAClB,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AACvB,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AAC7B,YAAY,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE;AAC5C,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE;AAClF,YAAY,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC9B,gBAAgB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,GAAG;AACnD,gBAAgB,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE;AACvD,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACxB,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AAClC,YAAY,UAAU,CAAC;AACvB,YAAY,IAAI,CAAC;AACjB,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AACjB,YAAY,KAAK,CAAC;AAClB,YAAY,YAAY,CAAC;AACzB,YAAY,WAAW;AACvB,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC1B,YAAY,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACzC,QAAQ,CAAC;AACT,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAChC,QAAQ,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK;AACpD,QAAQ,UAAU,CAAC,aAAa,GAAG;AACnC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC;AAClC,QAAQ,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC1C,IAAI,CAAC;AACL;AACA,IAAI,MAAM,CAAC,IAAI,CAAC;AAChB,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC;AACxC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AACxB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU;AAC/C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU;AAC/C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;AAC1E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI;AACvB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC3B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU;AAC7B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AAC9B,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC;AAChC,CAAC,EAAE;AACH,QAAQ,CAAC,OAAO,CAAC;AACjB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACT,IAAI,KAAK,CAAC;AACV,IAAI,UAAU,CAAC;AACf,IAAI,UAAU,CAAC;AACf,IAAI,WAAW,CAAC;AAChB,IAAI,IAAI,CAAC;AACT,IAAI,QAAQ,CAAC;AACb,IAAI,UAAU,CAAC;AACf,IAAI,WAAW;AACf,CAAC,CAAC,CAAC;AACH,IAAI,GAAG,CAAC,IAAI,CAAC;AACb,QAAQ,IAAI,CAAC;AACb,QAAQ,MAAM,CAAC;AACf,QAAQ,MAAM,CAAC;AACf,QAAQ,GAAG,CAAC;AACZ,QAAQ,WAAW,CAAC;AACpB,QAAQ,SAAS,CAAC;AAClB,QAAQ,IAAI,CAAC;AACb;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClC,QAAQ,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;AAClC,IAAI,CAAC;AACL,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,QAAQ,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;AACvC,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AACnE,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AACnE,QAAQ,MAAM,EAAE,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAChE,QAAQ,MAAM,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC7D,QAAQ,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC7D;AACA,QAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC,GAAG;AAClE,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC;AAC3C,YAAY,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC7E,YAAY,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC;AACtF,YAAY,EAAE,CAAC,GAAG,aAAa,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;AAC1D,gBAAgB,WAAW,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE;AAChF,YAAY,CAAC;AACb,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B,QAAQ,CAAC;AACT;AACA,QAAQ,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AAC7C,YAAY,UAAU,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACnE;AACA,QAAQ,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC9C,QAAQ,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE;AAC7E;AACA,QAAQ,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;AAC1B,YAAY,KAAK,CAAC;AAClB,YAAY,CAAC,CAAC;AACd,YAAY,CAAC,CAAC;AACd,YAAY,MAAM,CAAC;AACnB,YAAY,MAAM,CAAC;AACnB,YAAY,GAAG,CAAC;AAChB,YAAY,SAAS,CAAC;AACtB,YAAY,UAAU,CAAC,iBAAiB,CAAC;AACzC,YAAY,WAAW;AACvB,QAAQ,EAAE;AACV;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtC,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AACpC,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtC,YAAY,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,QAAQ,CAAC;AACT;AACA,QAAQ,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9C,IAAI,CAAC;AACL;AACA,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AAC1C,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9B;AACA,IAAI,MAAM,CAAC,IAAI,CAAC;AAChB,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAClE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU;AAC/C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI;AACnC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI;AACvB,CAAC,EAAE;AACH,QAAQ,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7C,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACxB,IAAI,UAAU,CAAC,YAAY,CAAC,MAAM,EAAE;AACpC,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AACtB,QAAQ,YAAY,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;AACxC,QAAQ,WAAW,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;AACtC,QAAQ,iBAAiB,CAAC,CAAC,UAAU,CAAC,iBAAiB,CAAC;AACxD,QAAQ,mBAAmB,CAAC,CAAC,UAAU,CAAC,mBAAmB,CAAC;AAC5D,QAAQ,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,EAAE;AAC3D,YAAY,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,EAAE;AAC/E,QAAQ,EAAE;AACV,QAAQ,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC3B,YAAY,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AACjC,QAAQ,CAAC;AACT,IAAI,GAAG;AACP,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC;AAC3D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU;AAC/C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI;AACnC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI;AACvB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK;AACvB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ;AAC3B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,CAAC,WAAW;AACtC,CAAC,EAAE;AACH,QAAQ,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC7E,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnB,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE;AAC5F,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC;AAC/C,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;AAClC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC;AAC9E,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;AACjG,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;AACvF,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;AAC1D,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,cAAc,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC;AAC1G,SAAS,EAAE;AACX,QAAQ,UAAU,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AAC1D,YAAY,IAAI,CAAC,CAAC,IAAI,CAAC;AACvB,YAAY,UAAU,CAAC,CAAC,UAAU,CAAC;AACnC,YAAY,IAAI,CAAC,CAAC,IAAI,CAAC;AACvB,YAAY,OAAO,CAAC,CAAC,QAAQ,CAAC;AAC9B,YAAY,WAAW,CAAC,CAAC,WAAW;AACpC,QAAQ,GAAG;AACX,QAAQ,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7B,QAAQ,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5B,QAAQ,MAAM,CAAC;AACf,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AAC5C,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;AACpF,QAAQ,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7B,QAAQ,MAAM,CAAC;AACf,IAAI,CAAC;AACL;AACA,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC7B,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,eAAe,GAAG;AACzD,QAAQ,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE;AACpE,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG;AACtF,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK;AAC7C,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACjC,QAAQ,MAAM,GAAG;AACjB,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK;AACzE,QAAQ,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACtC,IAAI,CAAC;AACL,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU;AAC/C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI;AACnC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK;AACvB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM;AACzB,CAAC,EAAE;AACH,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AACtE,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACtB;AACA,IAAI,QAAQ,CAAC,qBAAqB,EAAE,CAAC,CAAC;AACtC,QAAQ,SAAS,GAAG;AACpB,QAAQ,MAAM,CAAC,kBAAkB,CAAC;AAClC,IAAI,CAAC;AACL;AACA,IAAI,QAAQ,CAAC,kBAAkB,EAAE,CAAC,CAAC;AACnC,QAAQ,SAAS,GAAG;AACpB,QAAQ,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,YAAY,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AACjC,YAAY,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B,YAAY,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AAClC,gBAAgB,UAAU,CAAC,UAAU,CAAC,SAAS,EAAE;AACjD,oBAAoB,KAAK,CAAC,CAAC,KAAK,CAAC;AACjC,oBAAoB,IAAI,CAAC,CAAC,IAAI,CAAC;AAC/B,oBAAoB,MAAM,CAAC,CAAC,MAAM,CAAC;AACnC,oBAAoB,UAAU,CAAC,CAAC,UAAU;AAC1C,gBAAgB,GAAG;AACnB,YAAY,CAAC;AACb,YAAY,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACzC,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG;AAChF,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AACtF,KAAK,CAAC;AACN,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM;AACzB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACrC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACrB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AACvD,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;AAC5F,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;AAC5E,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,cAAc,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,UAAU,EAAE;AACtG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI;AACxF,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;AAC/E,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI;AAChF,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,qBAAqB,CAAC;AACrC,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AACjD,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC;AACnB,QAAQ,UAAU,CAAC,CAAC,UAAU,CAAC;AAC/B,QAAQ,WAAW,CAAC,CAAC,WAAW,CAAC;AACjC,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC;AACrB,QAAQ,qBAAqB,CAAC,CAAC,qBAAqB;AACpD,IAAI,GAAG;AACP,IAAI,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC;AAClF,IAAI,qBAAqB,KAAK;AAC9B,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI;AACnC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO;AAC3B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,QAAQ;AAC3C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,cAAc;AAC9C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe;AAClC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU;AAC/C,CAAC,EAAE;AACH,QAAQ,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,cAAc,CAAC,CAAC,eAAe,CAAC,CAAC,UAAU,CAAC,EAAE;AAC9F,IAAI,GAAG,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,GAAG;AAChD;AACA,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC;AACxD,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC;AACxD,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;AACpD,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;AACpD;AACA,IAAI,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG;AAC7C;AACA,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC;AAC1D,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC;AAC1D;AACA,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE;AACpE,QAAQ,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE;AACrE,QAAQ,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE;AACzE,QAAQ,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE;AAC1E,QAAQ,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACzD,QAAQ,mBAAmB,CAAC,CAAC,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC,UAAU,CAAC,EAAE;AAC7E;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACrB,QAAQ,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAClD,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC;AACxD,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK;AACnE,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC;AACvD,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK;AACnE,IAAI,CAAC;AACL;AACA,IAAI,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,SAAS,CAAC;AAChC,IAAI,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,KAAK,CAAC;AAC5B,IAAI,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC,mBAAmB,CAAC;AACjD,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,eAAe,CAAC;AACtC,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM;AAC5E,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;AACxB,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;AAChD,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;AAC7C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU;AAC/C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI;AACnC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK;AACxB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY;AAC/B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW;AAC9B,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;AACrB,CAAC,EAAE;AACH,QAAQ,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,WAAW,CAAC,EAAE;AAC/E,IAAI,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC;AACtD,QAAQ,SAAS,CAAC;AAClB,QAAQ,OAAO,CAAC;AAChB;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC7B,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC;AACtC,IAAI,CAAC;AACL;AACA,IAAI,SAAS,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;AAChD,IAAI,OAAO,KAAK,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvF;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACnC,QAAQ,OAAO,CAAC,EAAE,CAAC,YAAY,CAAC;AAChC,IAAI,CAAC;AACL;AACA,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;AAC3B;AACA,IAAI,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACtC;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzB,QAAQ,WAAW,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;AAC9D,QAAQ,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;AACzC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAC/C,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,CAAC;AACL;AACA,IAAI,MAAM,CAAC,KAAK,CAAC;AACjB,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;AAC3E,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;AACrE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK;AACtE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ;AAC1E,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC;AAC5D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AAC1E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAC5D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAClD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAClD,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;AACrB,CAAC,EAAE;AACH,QAAQ,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,IAAI,GAAG,CAAC,IAAI,CAAC;AACb,QAAQ,IAAI,CAAC;AACb,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACb;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,QAAQ,MAAM,CAAC,KAAK,CAAC;AACrB,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC/C,QAAQ,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AACjC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3B,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7C,gBAAgB,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;AACjC,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACnC,oBAAoB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,wBAAwB,MAAM,CAAC,KAAK,CAAC;AACrC,oBAAoB,CAAC;AACrB,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,CAAC;AACL;AACA,IAAI,MAAM,CAAC,CAAC;AACZ,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;AAC9C,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;AACpD,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI;AAC5C,IAAI,EAAE;AACN,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK;AACvE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC;AACvE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AAC1E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAC5D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAClD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAClD,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;AACrB,CAAC,EAAE;AACH,QAAQ,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7C,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC/C,QAAQ,MAAM,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACvD,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,QAAQ,MAAM,CAAC,CAAC;AAChB,aAAa,gBAAgB,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACrE,aAAa,gBAAgB,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACzE,aAAa,gBAAgB,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACzE,aAAa,gBAAgB,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1E,QAAQ,EAAE;AACV,IAAI,CAAC;AACL,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC;AACxD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AAC1E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAC5D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAClD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAClD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;AAChE,CAAC,EAAE;AACH,QAAQ,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACvD,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC;AACvB,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;AACzF,YAAY,KAAK;AACjB,QAAQ,EAAE;AACV,QAAQ,MAAM,CAAC;AACf,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;AACpC,IAAI,CAAC;AACL;AACA,IAAI,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AACzC,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM;AACzE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;AACrE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AAC1E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC;AAC7E,CAAC,EAAE;AACH,QAAQ,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3C,IAAI,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;AAC3B,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG;AAC1E,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC;AACpB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,YAAY;AAC3C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI;AACnC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;AACnD,CAAC,EAAE;AACH,QAAQ,CAAC,YAAY,CAAC,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7C,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AAC1B,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACtD,QAAQ,MAAM,CAAC,IAAI,CAAC;AACpB,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC9D,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AACpE,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,MAAM,CAAC,YAAY,CAAC;AACxB,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;AACtB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU;AAC/C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;AACzF,CAAC,EAAE;AACH,QAAQ,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC7C,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,oBAAoB,EAAE,CAAC,CAAC;AACnG,QAAQ,MAAM,CAAC;AACf,IAAI,CAAC;AACL;AACA,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AAC5B,IAAI,GAAG,CAAC,SAAS,CAAC;AAClB;AACA,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACf,QAAQ,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC7C,YAAY,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE;AAC7C,gBAAgB,UAAU,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE;AACnE,YAAY,EAAE,UAAU,CAAC,aAAa,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,uBAAuB,IAAI;AAC5E,IAAI,CAAC;AACL;AACA,IAAI,GAAG,CAAC,WAAW,CAAC;AACpB,IAAI,GAAG,CAAC,eAAe,CAAC;AACxB;AACA,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE;AACjD,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,mBAAmB,CAAC,IAAI,EAAE;AACzD;AACA,IAAI,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC/B,QAAQ,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,sBAAsB,CAAC,EAAE;AACxD,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE;AAChC,QAAQ,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC;AACnH,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC;AAC3B,QAAQ,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC;AACnE,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC;AAC5E,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK;AAChF,QAAQ,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,QAAQ,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,wBAAwB,GAAG;AACtD,QAAQ,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,8BAA8B,CAAC,WAAW,CAAC;AAC1E,YAAY,UAAU,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,EAAE;AACpD,YAAY,UAAU,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,GAAG;AACpD,IAAI,CAAC;AACL;AACA,IAAI,GAAG,CAAC,MAAM,CAAC;AACf,IAAI,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AACpB,QAAQ,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC;AAC3B,YAAY,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG;AACxE,YAAY,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC;AACzE,YAAY,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,gCAAgC,CAAC;AAC1E,gBAAgB,UAAU,CAAC,gBAAgB,CAAC,IAAI,EAAE;AAClD,gBAAgB,CAAC,qBAAqB,EAAE;AACxC,gBAAgB,CAAC,KAAK,GAAG,iBAAiB,EAAE;AAC5C,QAAQ,CAAC;AACT,QAAQ,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE;AAChD,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;AAC3E,IAAI,EAAE,CAAC,KAAK,CAAC,aAAa;AAC1B,IAAI,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC;AACvB,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,YAAY,UAAU,CAAC,OAAO,CAAC,kBAAkB,EAAE;AACnD,gBAAgB,OAAO,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC;AACrD,gBAAgB,SAAS,CAAC,CAAC,SAAS;AACpC,YAAY,GAAG;AACf,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,YAAY,UAAU,CAAC,OAAO,CAAC,kBAAkB,EAAE;AACnD,gBAAgB,OAAO,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,EAAE;AACtD,gBAAgB,KAAK,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,sBAAsB,CAAC;AAClE,oBAAoB,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;AAC9D,gBAAgB,SAAS,CAAC,CAAC,SAAS;AACpC,YAAY,GAAG;AACf,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AACzB,IAAI,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7B,QAAQ,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,EAAE;AAClD;AACA,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,wBAAwB,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE;AAC9E,QAAQ,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,GAAG;AAC5F,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,yBAAyB,CAAC,GAAG,EAAE;AACzE,QAAQ,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC1B,YAAY,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE;AACnD,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;AAC9B,YAAY,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,eAAe,EAAE;AAC3D,QAAQ,CAAC;AACT,QAAQ,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAE;AACxD;AACA,QAAQ,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AACxB,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,oBAAoB,CAAC,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnF,QAAQ,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,yBAAyB,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,GAAG;AACvG,QAAQ,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC1B,YAAY,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,WAAW,EAAE;AACjE,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;AAC9B,YAAY,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,SAAS,CAAC,eAAe,EAAE;AACzE,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7B,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACtE,YAAY,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE;AAChG,QAAQ,CAAC;AACT,QAAQ,IAAI,CAAC,CAAC;AACd,YAAY,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,oBAAoB,CAAC;AACxD,QAAQ,CAAC;AACT;AACA,QAAQ,UAAU,CAAC,OAAO,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,EAAE;AAChF,IAAI,CAAC;AACL;AACA,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACrD,QAAQ,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9B,QAAQ,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,CAAC,eAAe,CAAC,EAAE;AACjH,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B;AACA,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;AAChC,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC;AAC/C,aAAa,CAAC;AACd,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK;AAChC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AAC7C,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC/G,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC;AACjG,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI;AAClD,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,aAAa,EAAE;AACf,YAAY,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;AACzD,gBAAgB,UAAU,CAAC,CAAC,UAAU,CAAC;AACvC,gBAAgB,IAAI,CAAC,CAAC,IAAI;AAC1B,YAAY,GAAG;AACf,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACrB,QAAQ,UAAU,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,SAAS,CAAC,EAAE;AACvD,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC;AACvB,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,YAAY,UAAU,CAAC,OAAO,CAAC,uBAAuB,CAAC,SAAS,EAAE;AAClE,QAAQ,CAAC;AACT,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,YAAY,UAAU,CAAC,OAAO,CAAC,uBAAuB,CAAC,SAAS,EAAE;AAClE,QAAQ,CAAC;AACT,IAAI,CAAC;AACL;AACA,IAAI,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AACpB,QAAQ,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC1B,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,gBAAgB,UAAU,CAAC,OAAO,CAAC,kBAAkB,EAAE;AACvD,oBAAoB,OAAO,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC;AACzD,oBAAoB,SAAS,CAAC,CAAC,KAAK;AACpC,gBAAgB,GAAG;AACnB,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3D,gBAAgB,UAAU,CAAC,OAAO,CAAC,kBAAkB,EAAE;AACvD,oBAAoB,OAAO,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,EAAE;AAC1D,oBAAoB,KAAK,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,sBAAsB,CAAC;AACtE,wBAAwB,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;AAClE,oBAAoB,SAAS,CAAC,CAAC,KAAK;AACpC,gBAAgB,GAAG;AACnB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,QAAQ,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE;AACxC,YAAY,OAAO,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC;AACxC,YAAY,KAAK,CAAC,CAAC,WAAW,CAAC;AAC/B,YAAY,SAAS,CAAC,CAAC,eAAe,CAAC;AACvC,YAAY,kBAAkB,CAAC,CAAC,UAAU,CAAC,kBAAkB,CAAC;AAC9D,YAAY,MAAM,CAAC,CAAC,MAAM;AAC1B,QAAQ,GAAG;AACX,QAAQ,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAC1B,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3D,gBAAgB,UAAU,CAAC,OAAO,CAAC,uBAAuB,CAAC,KAAK,EAAE;AAClE,YAAY,CAAC;AACb,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,gBAAgB,UAAU,CAAC,OAAO,CAAC,uBAAuB,CAAC,KAAK,EAAE;AAClE,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,IAAI,aAAa,CAAC,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,EAAE;AAC3C,CAAC;AACD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;AACrE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU;AAC/C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;AACzF,CAAC,EAAE;AACH,QAAQ,CAAC,aAAa,CAAC,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACjD,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAChC,QAAQ,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC3D,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;AACtC,YAAY,GAAG,CAAC,CAAC;AACjB,gBAAgB,UAAU,CAAC,OAAO,CAAC,aAAa,CAAC;AACjD,oBAAoB,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE;AAC3D,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACxB,gBAAgB,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE;AACnC,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,CAAC;AACL,CAAC;AACD;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;ACx+DpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,EAAE,CAAC,OAAO,CAAC,KAAK;AAChB,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACtC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AAC7E,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AACvF,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AACnG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;AAC7B,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;AACzC,EAAE;AACF;AACA,EAAE,CAAC,OAAO,CAAC,KAAK;AAChB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACrC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AACrE,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AACjF,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AAChC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG;AACrB,EAAE;AACF;AACA,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACzB,IAAI,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACzB,QAAQ,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3B,QAAQ,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,QAAQ,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3B,IAAI,EAAE;AACN;AACA,IAAI,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC1B,QAAQ,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AAC3B,IAAI,EAAE;AACN;AACA,IAAI,kBAAkB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACpC,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACrC,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AAC5D,YAAY,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;AAC7C,YAAY,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;AAC/C,YAAY,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,GAAG;AAC5D,YAAY,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACjE,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM;AACpE,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM;AACtD,YAAY,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC;AACrC,IAAI,EAAE;AACN;AACA,IAAI,kBAAkB,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC;AACnD,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,kBAAkB,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1E,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC9E,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,kBAAkB,IAAI;AACvE,QAAQ,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,eAAe,CAAC;AAChD,IAAI,EAAE;AACN;AACA,IAAI,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7B,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,GAAG;AACzE,QAAQ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE;AAC/B,IAAI,EAAE;AACN;AACA,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACtD,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1C,gBAAgB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACzC,gBAAgB,MAAM,CAAC;AACvB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,OAAO,CAAC,IAAI,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;AACvF,IAAI,EAAE;AACN;AACA,IAAI,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC9B,QAAQ,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;AAClC,IAAI,CAAC;AACL,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS;AACnB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE;AAC/E,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC;AACpE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;AAC9D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE;AAC3E,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AAC7C,CAAC,EAAE;AACH,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACnC,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG;AAC5B;AACA,IAAI,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,kBAAkB,CAAC;AACnG,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG;AAC3B,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG;AAC5B,IAAI,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;AAChC,EAAE;AACF;AACA,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;AAC/C,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACzB,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;AAC3E,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AACtB,KAAK,EAAE;AACP,IAAI,cAAc,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAChC,QAAQ,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;AACxC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG;AACrF,KAAK,CAAC,CAAC,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS;AAC1F,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI;AAC3F,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM;AAC5F,KAAK,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC;AACtG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC;AACpE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AACtG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC;AACrE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI;AACnG,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK;AACpG,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC;AAClC,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACpC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AACjF,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AAC3F,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AAC7G,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AACvG;AACA,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;AACzC,QAAQ,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;AACtD;AACA,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE;AACpE,QAAQ,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC;AAC3B,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE;AAC1H,YAAY,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE;AACvF,gBAAgB,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK;AACpC,YAAY,GAAG;AACf;AACA,YAAY,IAAI,CAAC,kBAAkB,GAAG;AACtC,QAAQ,CAAC;AACT;AACA,QAAQ,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE;AAC1C,QAAQ,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,WAAW,CAAC;AACpD;AACA,QAAQ,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI;AACjF,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;AAC3F,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;AACnE,YAAY,GAAG,CAAC,SAAS,OAAO,CAAC,CAAC,IAAI,CAAC;AACvC,YAAY,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,YAAY,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC;AACvC,YAAY,GAAG,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,cAAc,CAAC;AACrF;AACA,YAAY,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACvE,gBAAgB,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE;AACxD,gBAAgB,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC;AAC/C;AACA,gBAAgB,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACxE,oBAAoB,QAAQ,CAAC;AAC7B,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC1C,oBAAoB,SAAS,OAAO,CAAC,CAAC,QAAQ,CAAC;AAC/C,oBAAoB,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC;AACxC,oBAAoB,eAAe,CAAC,CAAC,CAAC,cAAc,CAAC;AACrD,oBAAoB,QAAQ,CAAC;AAC7B,gBAAgB,CAAC;AACjB;AACA,gBAAgB,QAAQ,IAAI,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC;AACrD,gBAAgB,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC;AACtD,gBAAgB,SAAS,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;AAC7C,gBAAgB,UAAU,EAAE,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AAC9C;AACA,gBAAgB,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE;AAC5C,mBAAmB,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1E,oBAAoB,SAAS,OAAO,CAAC,CAAC,QAAQ,CAAC;AAC/C,oBAAoB,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC;AACxC,oBAAoB,eAAe,CAAC,CAAC,CAAC,cAAc,CAAC;AACrD,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,YAAY,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,gBAAgB,IAAI,CAAC,WAAW,CAAC,eAAe,EAAE;AAClD,gBAAgB,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC;AAChD,YAAY,CAAC;AACb,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,YAAY,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE;AAC9D,YAAY,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;AAC/B,YAAY,UAAU,CAAC,CAAC,OAAO,CAAC,UAAU;AAC1C,QAAQ,GAAG;AACX,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU;AACnD,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC3C,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,aAAa,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,GAAG;AACzF,QAAQ,GAAG,CAAC,UAAU,CAAC;AACvB,QAAQ,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D,YAAY,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE;AAChD,YAAY,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACzD,gBAAgB,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE;AAC7C,gBAAgB,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACjD,gBAAgB,CAAC,GAAG;AACpB,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,cAAc,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AACxC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,GAAG;AACtF,QAAQ,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE;AAC5C,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,WAAW,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;AACvC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,GAAG;AACvF,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;AACnC,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;AAC/C;AACA,QAAQ,IAAI,CAAC,MAAM,GAAG;AACtB,QAAQ,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC;AACA,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE;AAC5D,QAAQ,WAAW,CAAC,UAAU,CAAC,IAAI,EAAE;AACrC,QAAQ,EAAE,CAAC,EAAE,WAAW,CAAC,YAAY,GAAG,CAAC,CAAC;AAC1C,YAAY,WAAW,CAAC,OAAO,GAAG;AAClC,YAAY,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE;AACrD,YAAY,IAAI,CAAC,kBAAkB,GAAG;AACtC,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;AACpE,SAAS,CAAC;AACV,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ;AAC/B,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM;AACzC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;AAClG,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;AAClF,SAAS,EAAE;AACX,QAAQ,UAAU,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;AACvD,YAAY,IAAI,CAAC,CAAC,IAAI,CAAC;AACvB,YAAY,UAAU,CAAC,CAAC,UAAU;AAClC,QAAQ,GAAG;AACX,IAAI,CAAC;AACL,EAAE;AACF;AACA,EAAE,CAAC,aAAa,CAAC,GAAG;;ACjRpB,EAAE;AACF,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK;AACxB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU;AACzC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACrE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,GAAG,CAAC;AACP,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3E,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACtE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG;AACxE,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjE,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;AACzE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AACtE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACzE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS;AACvE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/D,CAAC,EAAE;AACH;AACA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACf;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK;AACf,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa;AAC1B,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,WAAW;AACrC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AAClE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAC3C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;AAClF,CAAC,GAAG;AACJ,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC/B,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACrB;AACA,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE;AAC7E;AACA,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/B;AACA,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AACjC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG;AACrB,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5B,IAAI,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC;AACnC,IAAI,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,KAAK,CAAC;AACpC,IAAI,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAClD,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC;AACvC,YAAY,KAAK,CAAC,YAAY,GAAG;AACjC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5C,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,IAAI,CAAC,YAAY,GAAG;AACxB,EAAE;AACF;AACA,EAAE,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG;AAClG,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC;AAC9B,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC;AAChE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;AAC/F,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI;AAChD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM;AACtD,KAAK,EAAE;AACP,IAAI,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACxC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,GAAG;AACnE,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,GAAG;AAClH;AACA,QAAQ,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG;AAChC,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AAC1C,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,GAAG;AACjF,YAAY,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AAC/C,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACrC,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC;AACtC,YAAY,IAAI,CAAC,YAAY,GAAG;AAChC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3C,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B;AACA,QAAQ,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,qBAAqB,EAAE;AACrE,QAAQ,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,qBAAqB,EAAE;AACnE;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AACrD,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI;AAC1B,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK;AACxC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC1G,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;AACpF,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;AACtC,YAAY,IAAI,CAAC,CAAC,IAAI;AACtB,QAAQ,CAAC,CAAC,EAAE;AACZ,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC;AAC3C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;AAChD,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC;AAC3E,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,GAAG;AACrF,QAAQ,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE;AACpC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AAC5D,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;AACzD,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AACpE,KAAK,EAAE;AACP,IAAI,cAAc,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACtC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,GAAG;AAC1E,QAAQ,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE;AAC9C,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;AAClD,KAAK,EAAE;AACP,IAAI,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC9B,QAAQ,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;AAClC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1E,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;AACjE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7C,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM;AACzD,KAAK,EAAE;AACP,IAAI,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3C,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,GAAG;AACxE,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,GAAG;AACxF;AACA,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE;AACnD;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5C,YAAY,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE;AACrE,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtD,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AAC1C,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;AAC7C,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B;AACA,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;AACjE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM;AACnC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK;AACxC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACzG,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG;AAC/E,SAAS,CAAC,CAAC,IAAI,CAAC,OAAO;AACvB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI;AAC5E,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI;AAClE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;AAC/C,YAAY,IAAI,CAAC,CAAC,IAAI,CAAC;AACvB,YAAY,aAAa,CAAC,CAAC,QAAQ,CAAC;AACpC,YAAY,QAAQ,CAAC,CAAC,KAAK;AAC3B,QAAQ,CAAC,CAAC,EAAE;AACZ,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC;AACtB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;AACnE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI;AACnD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM;AACtD,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,GAAG;AACtE;AACA,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE;AAClD,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,qBAAqB,EAAE;AACxE,QAAQ,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,qBAAqB,EAAE;AACtE,QAAQ,IAAI,CAAC,OAAO,GAAG;AACvB,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;AACvC,QAAQ,IAAI,CAAC,YAAY,GAAG;AAC5B,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B,QAAQ,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE;AACpC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACxB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI;AACnD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM;AACtD,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC3B,QAAQ,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AACtG,QAAQ,IAAI,CAAC,MAAM,CAAC,oBAAoB,GAAG;AAC3C,QAAQ,GAAG,CAAC,IAAI,CAAC;AACjB,QAAQ,GAAG,CAAC,CAAC,CAAC;AACd,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAClD,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE;AAClC,YAAY,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,qBAAqB,EAAE;AAC5E,YAAY,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,qBAAqB,EAAE;AAC1E,YAAY,IAAI,CAAC,OAAO,GAAG;AAC3B,QAAQ,CAAC;AACT;AACA,QAAQ,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;AACvC,QAAQ,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG;AACzB,QAAQ,IAAI,CAAC,YAAY,GAAG;AAC5B,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B;AACA,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACnD,YAAY,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE;AACnC,YAAY,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE;AACxC,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3D,KAAK,EAAE;AACP,IAAI,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC5B,QAAQ,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACxD,YAAY,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,GAAG;AACnC,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;AACnD,KAAK,EAAE;AACP,IAAI,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACxB,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7B,QAAQ,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACxD,YAAY,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC;AAC3D,QAAQ,CAAC;AACT;AACA,QAAQ,MAAM,CAAC,QAAQ,CAAC;AACxB,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;AACvB,KAAK,EAAE;AACP,IAAI,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AACtB,QAAQ,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACxD,YAAY,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,GAAG;AAClC,QAAQ,CAAC;AACT;AACA,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC;AAChC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;AAC1D,KAAK,EAAE;AACP,IAAI,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC3B,QAAQ,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACxD,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/C,gBAAgB,MAAM,CAAC,IAAI,CAAC;AAC5B,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,QAAQ,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;AAC/B,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AAC7G,KAAK,EAAE;AACP,IAAI,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC/B,QAAQ,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,GAAG;AACxC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG;AAChF,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI;AACnF,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE;AAClE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;AACvE,KAAK,EAAE;AACP,IAAI,gBAAgB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAClC,QAAQ,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC;AACnC,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO;AACvG,KAAK,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE;AAChH,KAAK,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI;AAC5G,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;AACtC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;AACnE,KAAK,EAAE;AACP,IAAI,oBAAoB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAC3C,QAAQ,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,KAAK,CAAC;AACxC,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC;AAC9C,YAAY,IAAI,CAAC,YAAY,GAAG;AAChC,YAAY,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5C,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,GAAG;AACP,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC;AACnE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC;AAC1D,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC;AAChG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAChG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAC5F,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAClG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACpG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AACxG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM;AACtD,KAAK,EAAE;AACP,IAAI,OAAO,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAChC,QAAQ,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG;AAChC,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC;AACvD,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,gBAAgB,CAAC;AAC3E,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,cAAc,CAAC;AACrE,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,iBAAiB,CAAC;AAC9E,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,kBAAkB,CAAC;AACjF,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,oBAAoB,CAAC;AACvF,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC;AAC9C,QAAQ,GAAG,CAAC,IAAI,CAAC;AACjB,QAAQ,EAAE,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;AACvC,YAAY,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;AAC3B,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE;AACxD,QAAQ,CAAC;AACT,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClB,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClB,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC;AAC/C;AACA,QAAQ,IAAI,CAAC,oBAAoB,CAAC,KAAK,EAAE;AACzC,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACtD,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACxC,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;AAC9C,oBAAoB,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC;AACnC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1B,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,oBAAoB,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC;AACnC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1B,gBAAgB,CAAC;AACjB,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE;AAClC,YAAY,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG;AACnC,YAAY,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AACzC,gBAAgB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AACjC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE;AAC5D,YAAY,CAAC;AACb;AACA,YAAY,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE;AACtD,YAAY,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAChE,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;AAC/C;AACA,YAAY,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE;AACpD,YAAY,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE;AAC9C;AACA,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;AAC1C,gBAAgB,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC;AAC/B,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,gBAAgB,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC;AAC/B,YAAY,CAAC;AACb,QAAQ,CAAC;AACT,QAAQ,IAAI,CAAC,oBAAoB,CAAC,IAAI,EAAE;AACxC,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC9B,QAAQ,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/E,QAAQ,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAClF,QAAQ,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC;AACxD;AACA,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AAClC,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACtD,YAAY,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAClD,YAAY,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;AAChB,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE;AACtC,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG;AAC1C,YAAY,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;AACzE,YAAY,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,GAAG,cAAc,GAAG;AACzE,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;AACvC,YAAY,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;AACtC,YAAY,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;AAC9D,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC;AAChE,YAAY,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC1D,gBAAgB,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE;AACtC,gBAAgB,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG;AAC1C,gBAAgB,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC;AACnE,oBAAoB,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE;AAC5D,gBAAgB,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,GAAG,cAAc,GAAG;AACzE,gBAAgB,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE;AACvD,gBAAgB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE;AACrD,gBAAgB,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,EAAE;AAC/E,gBAAgB,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,EAAE;AAClF,YAAY,CAAC;AACb;AACA,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE;AACjF,YAAY,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;AAC5C,gBAAgB,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC;AAC7D,gBAAgB,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,EAAE;AAC/D,QAAQ,CAAC;AACT;AACA,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE;AACvD,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE;AACtD,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC;AACxD,YAAY,GAAG;AACf,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;AACpE,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM;AACpC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK;AAC5C,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC7B,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7G,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAClF,aAAa,EAAE;AACf,YAAY,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI;AAClD,QAAQ,CAAC;AACT,IAAI,EAAE;AACN;AACA,IAAI,EAAE,CAAC,OAAO;AACd,IAAI,gBAAgB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AACtC,QAAQ,GAAG;AACX,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;AAC1C,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI;AAC7B,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK;AACxC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACzB,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACzG,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;AAClF,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9E,SAAS,EAAE;AACX,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACzD,IAAI,CAAC;AACL,GAAG;AACH;AACA,EAAE,CAAC,aAAa,CAAC,GAAG","file":"openseadragon.js","sourcesContent":["/*\n * OpenSeadragon\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/*\n * Portions of this source file taken from jQuery:\n *\n * Copyright 2011 John Resig\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/*\n * Portions of this source file taken from mattsnider.com:\n *\n * Copyright (c) 2006-2013 Matt Snider\n *\n * Permission is hereby granted, free of charge, to any person obtaining a\n * copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense,\n * and/or sell copies of the Software, and to permit persons to whom the\n * Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included\n * in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT\n * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR\n * THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n\n/**\n * @namespace OpenSeadragon\n * @version openseadragon 2.3.1\n * @classdesc The root namespace for OpenSeadragon. All utility methods\n * and classes are defined on or below this namespace.\n *\n */\n\n\n// Typedefs\n\n /**\n * All required and optional settings for instantiating a new instance of an OpenSeadragon image viewer.\n *\n * @typedef {Object} Options\n * @memberof OpenSeadragon\n *\n * @property {String} id\n * Id of the element to append the viewer's container element to. If not provided, the 'element' property must be provided.\n * If both the element and id properties are specified, the viewer is appended to the element provided in the element property.\n *\n * @property {Element} element\n * The element to append the viewer's container element to. If not provided, the 'id' property must be provided.\n * If both the element and id properties are specified, the viewer is appended to the element provided in the element property.\n *\n * @property {Array|String|Function|Object} [tileSources=null]\n * Tile source(s) to open initially. This is a complex parameter; see\n * {@link OpenSeadragon.Viewer#open} for details.\n *\n * @property {Number} [tabIndex=0]\n * Tabbing order index to assign to the viewer element. Positive values are selected in increasing order. When tabIndex is 0\n * source order is used. A negative value omits the viewer from the tabbing order.\n *\n * @property {Array} overlays Array of objects defining permanent overlays of\n * the viewer. The overlays added via this option and later removed with\n * {@link OpenSeadragon.Viewer#removeOverlay} will be added back when a new\n * image is opened.\n * To add overlays which can be definitively removed, one must use\n * {@link OpenSeadragon.Viewer#addOverlay}\n * If displaying a sequence of images, the overlays can be associated\n * with a specific page by passing the overlays array to the page's\n * tile source configuration.\n * Expected properties:\n * * x, y, (or px, py for pixel coordinates) to define the location.\n * * width, height in point if using x,y or in pixels if using px,py. If width\n * and height are specified, the overlay size is adjusted when zooming,\n * otherwise the size stays the size of the content (or the size defined by CSS).\n * * className to associate a class to the overlay\n * * id to set the overlay element. If an element with this id already exists,\n * it is reused, otherwise it is created. If not specified, a new element is\n * created.\n * * placement a string to define the relative position to the viewport.\n * Only used if no width and height are specified. Default: 'TOP_LEFT'.\n * See {@link OpenSeadragon.Placement} for possible values.\n *\n * @property {String} [xmlPath=null]\n * DEPRECATED. A relative path to load a DZI file from the server.\n * Prefer the newer Options.tileSources.\n *\n * @property {String} [prefixUrl='/images/']\n * Prepends the prefixUrl to navImages paths, which is very useful\n * since the default paths are rarely useful for production\n * environments.\n *\n * @property {OpenSeadragon.NavImages} [navImages]\n * An object with a property for each button or other built-in navigation\n * control, eg the current 'zoomIn', 'zoomOut', 'home', and 'fullpage'.\n * Each of those in turn provides an image path for each state of the button\n * or navigation control, eg 'REST', 'GROUP', 'HOVER', 'PRESS'. Finally the\n * image paths, by default assume there is a folder on the servers root path\n * called '/images', eg '/images/zoomin_rest.png'. If you need to adjust\n * these paths, prefer setting the option.prefixUrl rather than overriding\n * every image path directly through this setting.\n *\n * @property {Boolean} [debugMode=false]\n * TODO: provide an in-screen panel providing event detail feedback.\n *\n * @property {String} [debugGridColor=['#437AB2', '#1B9E77', '#D95F02', '#7570B3', '#E7298A', '#66A61E', '#E6AB02', '#A6761D', '#666666']]\n * The colors of grids in debug mode. Each tiled image's grid uses a consecutive color.\n * If there are more tiled images than provided colors, the color vector is recycled.\n *\n * @property {Number} [blendTime=0]\n * Specifies the duration of animation as higher or lower level tiles are\n * replacing the existing tile.\n *\n * @property {Boolean} [alwaysBlend=false]\n * Forces the tile to always blend. By default the tiles skip blending\n * when the blendTime is surpassed and the current animation frame would\n * not complete the blend.\n *\n * @property {Boolean} [autoHideControls=true]\n * If the user stops interacting with the viewport, fade the navigation\n * controls. Useful for presentation since the controls are by default\n * floated on top of the image the user is viewing.\n *\n * @property {Boolean} [immediateRender=false]\n * Render the best closest level first, ignoring the lowering levels which\n * provide the effect of very blurry to sharp. It is recommended to change\n * setting to true for mobile devices.\n *\n * @property {Number} [defaultZoomLevel=0]\n * Zoom level to use when image is first opened or the home button is clicked.\n * If 0, adjusts to fit viewer.\n *\n * @property {Number} [opacity=1]\n * Default proportional opacity of the tiled images (1=opaque, 0=hidden)\n * Hidden images do not draw and only load when preloading is allowed.\n *\n * @property {Boolean} [preload=false]\n * Default switch for loading hidden images (true loads, false blocks)\n *\n * @property {String} [compositeOperation=null]\n * Valid values are 'source-over', 'source-atop', 'source-in', 'source-out',\n * 'destination-over', 'destination-atop', 'destination-in',\n * 'destination-out', 'lighter', 'copy' or 'xor'\n *\n * @property {String|CanvasGradient|CanvasPattern|Function} [placeholderFillStyle=null]\n * Draws a colored rectangle behind the tile if it is not loaded yet.\n * You can pass a CSS color value like \"#FF8800\".\n * When passing a function the tiledImage and canvas context are available as argument which is useful when you draw a gradient or pattern.\n *\n * @property {Number} [degrees=0]\n * Initial rotation.\n *\n * @property {Number} [minZoomLevel=null]\n *\n * @property {Number} [maxZoomLevel=null]\n *\n * @property {Boolean} [homeFillsViewer=false]\n * Make the 'home' button fill the viewer and clip the image, instead\n * of fitting the image to the viewer and letterboxing.\n *\n * @property {Boolean} [panHorizontal=true]\n * Allow horizontal pan.\n *\n * @property {Boolean} [panVertical=true]\n * Allow vertical pan.\n *\n * @property {Boolean} [constrainDuringPan=false]\n *\n * @property {Boolean} [wrapHorizontal=false]\n * Set to true to force the image to wrap horizontally within the viewport.\n * Useful for maps or images representing the surface of a sphere or cylinder.\n *\n * @property {Boolean} [wrapVertical=false]\n * Set to true to force the image to wrap vertically within the viewport.\n * Useful for maps or images representing the surface of a sphere or cylinder.\n *\n * @property {Number} [minZoomImageRatio=0.9]\n * The minimum percentage ( expressed as a number between 0 and 1 ) of\n * the viewport height or width at which the zoom out will be constrained.\n * Setting it to 0, for example will allow you to zoom out infinity.\n *\n * @property {Number} [maxZoomPixelRatio=1.1]\n * The maximum ratio to allow a zoom-in to affect the highest level pixel\n * ratio. This can be set to Infinity to allow 'infinite' zooming into the\n * image though it is less effective visually if the HTML5 Canvas is not\n * availble on the viewing device.\n *\n * @property {Number} [smoothTileEdgesMinZoom=1.1]\n * A zoom percentage ( where 1 is 100% ) of the highest resolution level.\n * When zoomed in beyond this value alternative compositing will be used to\n * smooth out the edges between tiles. This will have a performance impact.\n * Can be set to Infinity to turn it off.\n * Note: This setting is ignored on iOS devices due to a known bug (See {@link https://github.com/openseadragon/openseadragon/issues/952})\n *\n * @property {Boolean} [iOSDevice=?]\n * True if running on an iOS device, false otherwise.\n * Used to disable certain features that behave differently on iOS devices.\n *\n * @property {Boolean} [autoResize=true]\n * Set to false to prevent polling for viewer size changes. Useful for providing custom resize behavior.\n *\n * @property {Boolean} [preserveImageSizeOnResize=false]\n * Set to true to have the image size preserved when the viewer is resized. This requires autoResize=true (default).\n *\n * @property {Number} [minScrollDeltaTime=50]\n * Number of milliseconds between canvas-scroll events. This value helps normalize the rate of canvas-scroll\n * events between different devices, causing the faster devices to slow down enough to make the zoom control\n * more manageable.\n *\n * @property {Number} [pixelsPerWheelLine=40]\n * For pixel-resolution scrolling devices, the number of pixels equal to one scroll line.\n *\n * @property {Number} [visibilityRatio=0.5]\n * The percentage ( as a number from 0 to 1 ) of the source image which\n * must be kept within the viewport. If the image is dragged beyond that\n * limit, it will 'bounce' back until the minimum visibility ratio is\n * achieved. Setting this to 0 and wrapHorizontal ( or wrapVertical ) to\n * true will provide the effect of an infinitely scrolling viewport.\n *\n * @property {Object} [viewportMargins={}]\n * Pushes the \"home\" region in from the sides by the specified amounts.\n * Possible subproperties (Numbers, in screen coordinates): left, top, right, bottom.\n *\n * @property {Number} [imageLoaderLimit=0]\n * The maximum number of image requests to make concurrently. By default\n * it is set to 0 allowing the browser to make the maximum number of\n * image requests in parallel as allowed by the browsers policy.\n *\n * @property {Number} [clickTimeThreshold=300]\n * The number of milliseconds within which a pointer down-up event combination\n * will be treated as a click gesture.\n *\n * @property {Number} [clickDistThreshold=5]\n * The maximum distance allowed between a pointer down event and a pointer up event\n * to be treated as a click gesture.\n *\n * @property {Number} [dblClickTimeThreshold=300]\n * The number of milliseconds within which two pointer down-up event combinations\n * will be treated as a double-click gesture.\n *\n * @property {Number} [dblClickDistThreshold=20]\n * The maximum distance allowed between two pointer click events\n * to be treated as a double-click gesture.\n *\n * @property {Number} [springStiffness=6.5]\n *\n * @property {Number} [animationTime=1.2]\n * Specifies the animation duration per each {@link OpenSeadragon.Spring}\n * which occur when the image is dragged or zoomed.\n *\n * @property {OpenSeadragon.GestureSettings} [gestureSettingsMouse]\n * Settings for gestures generated by a mouse pointer device. (See {@link OpenSeadragon.GestureSettings})\n * @property {Boolean} [gestureSettingsMouse.scrollToZoom=true] - Zoom on scroll gesture\n * @property {Boolean} [gestureSettingsMouse.clickToZoom=true] - Zoom on click gesture\n * @property {Boolean} [gestureSettingsMouse.dblClickToZoom=false] - Zoom on double-click gesture. Note: If set to true\n * then clickToZoom should be set to false to prevent multiple zooms.\n * @property {Boolean} [gestureSettingsMouse.pinchToZoom=false] - Zoom on pinch gesture\n * @property {Boolean} [gestureSettingsMouse.flickEnabled=false] - Enable flick gesture\n * @property {Number} [gestureSettingsMouse.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)\n * @property {Number} [gestureSettingsMouse.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture\n * @property {Boolean} [gestureSettingsMouse.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers.\n *\n * @property {OpenSeadragon.GestureSettings} [gestureSettingsTouch]\n * Settings for gestures generated by a touch pointer device. (See {@link OpenSeadragon.GestureSettings})\n * @property {Boolean} [gestureSettingsTouch.scrollToZoom=false] - Zoom on scroll gesture\n * @property {Boolean} [gestureSettingsTouch.clickToZoom=false] - Zoom on click gesture\n * @property {Boolean} [gestureSettingsTouch.dblClickToZoom=true] - Zoom on double-click gesture. Note: If set to true\n * then clickToZoom should be set to false to prevent multiple zooms.\n * @property {Boolean} [gestureSettingsTouch.pinchToZoom=true] - Zoom on pinch gesture\n * @property {Boolean} [gestureSettingsTouch.flickEnabled=true] - Enable flick gesture\n * @property {Number} [gestureSettingsTouch.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)\n * @property {Number} [gestureSettingsTouch.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture\n * @property {Boolean} [gestureSettingsTouch.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers.\n *\n * @property {OpenSeadragon.GestureSettings} [gestureSettingsPen]\n * Settings for gestures generated by a pen pointer device. (See {@link OpenSeadragon.GestureSettings})\n * @property {Boolean} [gestureSettingsPen.scrollToZoom=false] - Zoom on scroll gesture\n * @property {Boolean} [gestureSettingsPen.clickToZoom=true] - Zoom on click gesture\n * @property {Boolean} [gestureSettingsPen.dblClickToZoom=false] - Zoom on double-click gesture. Note: If set to true\n * then clickToZoom should be set to false to prevent multiple zooms.\n * @property {Boolean} [gestureSettingsPen.pinchToZoom=false] - Zoom on pinch gesture\n * @property {Boolean} [gestureSettingsPen.flickEnabled=false] - Enable flick gesture\n * @property {Number} [gestureSettingsPen.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)\n * @property {Number} [gestureSettingsPen.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture\n * @property {Boolean} [gestureSettingsPen.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers.\n *\n * @property {OpenSeadragon.GestureSettings} [gestureSettingsUnknown]\n * Settings for gestures generated by unknown pointer devices. (See {@link OpenSeadragon.GestureSettings})\n * @property {Boolean} [gestureSettingsUnknown.scrollToZoom=true] - Zoom on scroll gesture\n * @property {Boolean} [gestureSettingsUnknown.clickToZoom=false] - Zoom on click gesture\n * @property {Boolean} [gestureSettingsUnknown.dblClickToZoom=true] - Zoom on double-click gesture. Note: If set to true\n * then clickToZoom should be set to false to prevent multiple zooms.\n * @property {Boolean} [gestureSettingsUnknown.pinchToZoom=true] - Zoom on pinch gesture\n * @property {Boolean} [gestureSettingsUnknown.flickEnabled=true] - Enable flick gesture\n * @property {Number} [gestureSettingsUnknown.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)\n * @property {Number} [gestureSettingsUnknown.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture\n * @property {Boolean} [gestureSettingsUnknown.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers.\n *\n * @property {Number} [zoomPerClick=2.0]\n * The \"zoom distance\" per mouse click or touch tap. Note: Setting this to 1.0 effectively disables the click-to-zoom feature (also see gestureSettings[Mouse|Touch|Pen].clickToZoom/dblClickToZoom).\n *\n * @property {Number} [zoomPerScroll=1.2]\n * The \"zoom distance\" per mouse scroll or touch pinch. Note: Setting this to 1.0 effectively disables the mouse-wheel zoom feature (also see gestureSettings[Mouse|Touch|Pen].scrollToZoom}).\n *\n * @property {Number} [zoomPerSecond=1.0]\n * The number of seconds to animate a single zoom event over.\n *\n * @property {Boolean} [showNavigator=false]\n * Set to true to make the navigator minimap appear.\n *\n * @property {String} [navigatorId=navigator-GENERATED DATE]\n * The ID of a div to hold the navigator minimap.\n * If an ID is specified, the navigatorPosition, navigatorSizeRatio, navigatorMaintainSizeRatio, navigator[Top|Left|Height|Width] and navigatorAutoFade options will be ignored.\n * If an ID is not specified, a div element will be generated and placed on top of the main image.\n *\n * @property {String} [navigatorPosition='TOP_RIGHT']\n * Valid values are 'TOP_LEFT', 'TOP_RIGHT', 'BOTTOM_LEFT', 'BOTTOM_RIGHT', or 'ABSOLUTE'.
      \n * If 'ABSOLUTE' is specified, then navigator[Top|Left|Height|Width] determines the size and position of the navigator minimap in the viewer, and navigatorSizeRatio and navigatorMaintainSizeRatio are ignored.
      \n * For 'TOP_LEFT', 'TOP_RIGHT', 'BOTTOM_LEFT', and 'BOTTOM_RIGHT', the navigatorSizeRatio or navigator[Height|Width] values determine the size of the navigator minimap.\n *\n * @property {Number} [navigatorSizeRatio=0.2]\n * Ratio of navigator size to viewer size. Ignored if navigator[Height|Width] are specified.\n *\n * @property {Boolean} [navigatorMaintainSizeRatio=false]\n * If true, the navigator minimap is resized (using navigatorSizeRatio) when the viewer size changes.\n *\n * @property {Number|String} [navigatorTop=null]\n * Specifies the location of the navigator minimap (see navigatorPosition).\n *\n * @property {Number|String} [navigatorLeft=null]\n * Specifies the location of the navigator minimap (see navigatorPosition).\n *\n * @property {Number|String} [navigatorHeight=null]\n * Specifies the size of the navigator minimap (see navigatorPosition).\n * If specified, navigatorSizeRatio and navigatorMaintainSizeRatio are ignored.\n *\n * @property {Number|String} [navigatorWidth=null]\n * Specifies the size of the navigator minimap (see navigatorPosition).\n * If specified, navigatorSizeRatio and navigatorMaintainSizeRatio are ignored.\n *\n * @property {Boolean} [navigatorAutoResize=true]\n * Set to false to prevent polling for navigator size changes. Useful for providing custom resize behavior.\n * Setting to false can also improve performance when the navigator is configured to a fixed size.\n *\n * @property {Boolean} [navigatorAutoFade=true]\n * If the user stops interacting with the viewport, fade the navigator minimap.\n * Setting to false will make the navigator minimap always visible.\n *\n * @property {Boolean} [navigatorRotate=true]\n * If true, the navigator will be rotated together with the viewer.\n *\n * @property {Number} [controlsFadeDelay=2000]\n * The number of milliseconds to wait once the user has stopped interacting\n * with the interface before begining to fade the controls. Assumes\n * showNavigationControl and autoHideControls are both true.\n *\n * @property {Number} [controlsFadeLength=1500]\n * The number of milliseconds to animate the controls fading out.\n *\n * @property {Number} [maxImageCacheCount=200]\n * The max number of images we should keep in memory (per drawer).\n *\n * @property {Number} [timeout=30000]\n * The max number of milliseconds that an image job may take to complete.\n *\n * @property {Boolean} [useCanvas=true]\n * Set to false to not use an HTML canvas element for image rendering even if canvas is supported.\n *\n * @property {Number} [minPixelRatio=0.5]\n * The higher the minPixelRatio, the lower the quality of the image that\n * is considered sufficient to stop rendering a given zoom level. For\n * example, if you are targeting mobile devices with less bandwith you may\n * try setting this to 1.5 or higher.\n *\n * @property {Boolean} [mouseNavEnabled=true]\n * Is the user able to interact with the image via mouse or touch. Default\n * interactions include draging the image in a plane, and zooming in toward\n * and away from the image.\n *\n * @property {Boolean} [showNavigationControl=true]\n * Set to false to prevent the appearance of the default navigation controls.
      \n * Note that if set to false, the customs buttons set by the options\n * zoomInButton, zoomOutButton etc, are rendered inactive.\n *\n * @property {OpenSeadragon.ControlAnchor} [navigationControlAnchor=TOP_LEFT]\n * Placement of the default navigation controls.\n * To set the placement of the sequence controls, see the\n * sequenceControlAnchor option.\n *\n * @property {Boolean} [showZoomControl=true]\n * If true then + and - buttons to zoom in and out are displayed.
      \n * Note: {@link OpenSeadragon.Options.showNavigationControl} is overriding\n * this setting when set to false.\n *\n * @property {Boolean} [showHomeControl=true]\n * If true then the 'Go home' button is displayed to go back to the original\n * zoom and pan.
      \n * Note: {@link OpenSeadragon.Options.showNavigationControl} is overriding\n * this setting when set to false.\n *\n * @property {Boolean} [showFullPageControl=true]\n * If true then the 'Toggle full page' button is displayed to switch\n * between full page and normal mode.
      \n * Note: {@link OpenSeadragon.Options.showNavigationControl} is overriding\n * this setting when set to false.\n *\n * @property {Boolean} [showRotationControl=false]\n * If true then the rotate left/right controls will be displayed as part of the\n * standard controls. This is also subject to the browser support for rotate\n * (e.g. viewer.drawer.canRotate()).
      \n * Note: {@link OpenSeadragon.Options.showNavigationControl} is overriding\n * this setting when set to false.\n *\n * @property {Boolean} [showSequenceControl=true]\n * If sequenceMode is true, then provide buttons for navigating forward and\n * backward through the images.\n *\n * @property {OpenSeadragon.ControlAnchor} [sequenceControlAnchor=TOP_LEFT]\n * Placement of the default sequence controls.\n *\n * @property {Boolean} [navPrevNextWrap=false]\n * If true then the 'previous' button will wrap to the last image when\n * viewing the first image and the 'next' button will wrap to the first\n * image when viewing the last image.\n *\n * @property {String} zoomInButton\n * Set the id of the custom 'Zoom in' button to use.\n * This is useful to have a custom button anywhere in the web page.
      \n * To only change the button images, consider using\n * {@link OpenSeadragon.Options.navImages}\n *\n * @property {String} zoomOutButton\n * Set the id of the custom 'Zoom out' button to use.\n * This is useful to have a custom button anywhere in the web page.
      \n * To only change the button images, consider using\n * {@link OpenSeadragon.Options.navImages}\n *\n * @property {String} homeButton\n * Set the id of the custom 'Go home' button to use.\n * This is useful to have a custom button anywhere in the web page.
      \n * To only change the button images, consider using\n * {@link OpenSeadragon.Options.navImages}\n *\n * @property {String} fullPageButton\n * Set the id of the custom 'Toggle full page' button to use.\n * This is useful to have a custom button anywhere in the web page.
      \n * To only change the button images, consider using\n * {@link OpenSeadragon.Options.navImages}\n *\n * @property {String} rotateLeftButton\n * Set the id of the custom 'Rotate left' button to use.\n * This is useful to have a custom button anywhere in the web page.
      \n * To only change the button images, consider using\n * {@link OpenSeadragon.Options.navImages}\n *\n * @property {String} rotateRightButton\n * Set the id of the custom 'Rotate right' button to use.\n * This is useful to have a custom button anywhere in the web page.
      \n * To only change the button images, consider using\n * {@link OpenSeadragon.Options.navImages}\n *\n * @property {String} previousButton\n * Set the id of the custom 'Previous page' button to use.\n * This is useful to have a custom button anywhere in the web page.
      \n * To only change the button images, consider using\n * {@link OpenSeadragon.Options.navImages}\n *\n * @property {String} nextButton\n * Set the id of the custom 'Next page' button to use.\n * This is useful to have a custom button anywhere in the web page.
      \n * To only change the button images, consider using\n * {@link OpenSeadragon.Options.navImages}\n *\n * @property {Boolean} [sequenceMode=false]\n * Set to true to have the viewer treat your tilesources as a sequence of images to\n * be opened one at a time rather than all at once.\n *\n * @property {Number} [initialPage=0]\n * If sequenceMode is true, display this page initially.\n *\n * @property {Boolean} [preserveViewport=false]\n * If sequenceMode is true, then normally navigating through each image resets the\n * viewport to 'home' position. If preserveViewport is set to true, then the viewport\n * position is preserved when navigating between images in the sequence.\n *\n * @property {Boolean} [preserveOverlays=false]\n * If sequenceMode is true, then normally navigating through each image\n * resets the overlays.\n * If preserveOverlays is set to true, then the overlays added with {@link OpenSeadragon.Viewer#addOverlay}\n * are preserved when navigating between images in the sequence.\n * Note: setting preserveOverlays overrides any overlays specified in the global\n * \"overlays\" option for the Viewer. It's also not compatible with specifying\n * per-tileSource overlays via the options, as those overlays will persist\n * even after the tileSource is closed.\n *\n * @property {Boolean} [showReferenceStrip=false]\n * If sequenceMode is true, then display a scrolling strip of image thumbnails for\n * navigating through the images.\n *\n * @property {String} [referenceStripScroll='horizontal']\n *\n * @property {Element} [referenceStripElement=null]\n *\n * @property {Number} [referenceStripHeight=null]\n *\n * @property {Number} [referenceStripWidth=null]\n *\n * @property {String} [referenceStripPosition='BOTTOM_LEFT']\n *\n * @property {Number} [referenceStripSizeRatio=0.2]\n *\n * @property {Boolean} [collectionMode=false]\n * Set to true to have the viewer arrange your TiledImages in a grid or line.\n *\n * @property {Number} [collectionRows=3]\n * If collectionMode is true, specifies how many rows the grid should have. Use 1 to make a line.\n * If collectionLayout is 'vertical', specifies how many columns instead.\n *\n * @property {Number} [collectionColumns=0]\n * If collectionMode is true, specifies how many columns the grid should have. Use 1 to make a line.\n * If collectionLayout is 'vertical', specifies how many rows instead. Ignored if collectionRows is not set to a falsy value.\n *\n * @property {String} [collectionLayout='horizontal']\n * If collectionMode is true, specifies whether to arrange vertically or horizontally.\n *\n * @property {Number} [collectionTileSize=800]\n * If collectionMode is true, specifies the size, in viewport coordinates, for each TiledImage to fit into.\n * The TiledImage will be centered within a square of the specified size.\n *\n * @property {Number} [collectionTileMargin=80]\n * If collectionMode is true, specifies the margin, in viewport coordinates, between each TiledImage.\n *\n * @property {String|Boolean} [crossOriginPolicy=false]\n * Valid values are 'Anonymous', 'use-credentials', and false. If false, canvas requests will\n * not use CORS, and the canvas will be tainted.\n *\n * @property {Boolean} [ajaxWithCredentials=false]\n * Whether to set the withCredentials XHR flag for AJAX requests.\n * Note that this can be overridden at the {@link OpenSeadragon.TileSource} level.\n *\n * @property {Boolean} [loadTilesWithAjax=false]\n * Whether to load tile data using AJAX requests.\n * Note that this can be overridden at the {@link OpenSeadragon.TileSource} level.\n *\n * @property {Object} [ajaxHeaders={}]\n * A set of headers to include when making AJAX requests for tile sources or tiles.\n *\n */\n\n /**\n * Settings for gestures generated by a pointer device.\n *\n * @typedef {Object} GestureSettings\n * @memberof OpenSeadragon\n *\n * @property {Boolean} scrollToZoom\n * Set to false to disable zooming on scroll gestures.\n *\n * @property {Boolean} clickToZoom\n * Set to false to disable zooming on click gestures.\n *\n * @property {Boolean} dblClickToZoom\n * Set to false to disable zooming on double-click gestures. Note: If set to true\n * then clickToZoom should be set to false to prevent multiple zooms.\n *\n * @property {Boolean} pinchToZoom\n * Set to false to disable zooming on pinch gestures.\n *\n * @property {Boolean} flickEnabled\n * Set to false to disable the kinetic panning effect (flick) at the end of a drag gesture.\n *\n * @property {Number} flickMinSpeed\n * If flickEnabled is true, the minimum speed (in pixels-per-second) required to cause the kinetic panning effect (flick) at the end of a drag gesture.\n *\n * @property {Number} flickMomentum\n * If flickEnabled is true, a constant multiplied by the velocity to determine the distance of the kinetic panning effect (flick) at the end of a drag gesture.\n * A larger value will make the flick feel \"lighter\", while a smaller value will make the flick feel \"heavier\".\n * Note: springStiffness and animationTime also affect the \"spring\" used to stop the flick animation.\n *\n */\n\n/**\n * The names for the image resources used for the image navigation buttons.\n *\n * @typedef {Object} NavImages\n * @memberof OpenSeadragon\n *\n * @property {Object} zoomIn - Images for the zoom-in button.\n * @property {String} zoomIn.REST\n * @property {String} zoomIn.GROUP\n * @property {String} zoomIn.HOVER\n * @property {String} zoomIn.DOWN\n *\n * @property {Object} zoomOut - Images for the zoom-out button.\n * @property {String} zoomOut.REST\n * @property {String} zoomOut.GROUP\n * @property {String} zoomOut.HOVER\n * @property {String} zoomOut.DOWN\n *\n * @property {Object} home - Images for the home button.\n * @property {String} home.REST\n * @property {String} home.GROUP\n * @property {String} home.HOVER\n * @property {String} home.DOWN\n *\n * @property {Object} fullpage - Images for the full-page button.\n * @property {String} fullpage.REST\n * @property {String} fullpage.GROUP\n * @property {String} fullpage.HOVER\n * @property {String} fullpage.DOWN\n *\n * @property {Object} rotateleft - Images for the rotate left button.\n * @property {String} rotateleft.REST\n * @property {String} rotateleft.GROUP\n * @property {String} rotateleft.HOVER\n * @property {String} rotateleft.DOWN\n *\n * @property {Object} rotateright - Images for the rotate right button.\n * @property {String} rotateright.REST\n * @property {String} rotateright.GROUP\n * @property {String} rotateright.HOVER\n * @property {String} rotateright.DOWN\n *\n * @property {Object} previous - Images for the previous button.\n * @property {String} previous.REST\n * @property {String} previous.GROUP\n * @property {String} previous.HOVER\n * @property {String} previous.DOWN\n *\n * @property {Object} next - Images for the next button.\n * @property {String} next.REST\n * @property {String} next.GROUP\n * @property {String} next.HOVER\n * @property {String} next.DOWN\n *\n */\n\n\nfunction OpenSeadragon( options ){\n return new OpenSeadragon.Viewer( options );\n}\n\n(function( $ ){\n\n\n /**\n * The OpenSeadragon version.\n *\n * @member {Object} OpenSeadragon.version\n * @property {String} versionStr - The version number as a string ('major.minor.revision').\n * @property {Number} major - The major version number.\n * @property {Number} minor - The minor version number.\n * @property {Number} revision - The revision number.\n * @since 1.0.0\n */\n $.version = {\n versionStr: '2.3.1',\n major: parseInt('2', 10),\n minor: parseInt('3', 10),\n revision: parseInt('1', 10)\n };\n\n\n /**\n * Taken from jquery 1.6.1\n * [[Class]] -> type pairs\n * @private\n */\n var class2type = {\n '[object Boolean]': 'boolean',\n '[object Number]': 'number',\n '[object String]': 'string',\n '[object Function]': 'function',\n '[object Array]': 'array',\n '[object Date]': 'date',\n '[object RegExp]': 'regexp',\n '[object Object]': 'object'\n },\n // Save a reference to some core methods\n toString = Object.prototype.toString,\n hasOwn = Object.prototype.hasOwnProperty;\n\n /**\n * Taken from jQuery 1.6.1\n * @function isFunction\n * @memberof OpenSeadragon\n * @see {@link http://www.jquery.com/ jQuery}\n */\n $.isFunction = function( obj ) {\n return $.type(obj) === \"function\";\n };\n\n\n /**\n * Taken from jQuery 1.6.1\n * @function isArray\n * @memberof OpenSeadragon\n * @see {@link http://www.jquery.com/ jQuery}\n */\n $.isArray = Array.isArray || function( obj ) {\n return $.type(obj) === \"array\";\n };\n\n\n /**\n * A crude way of determining if an object is a window.\n * Taken from jQuery 1.6.1\n * @function isWindow\n * @memberof OpenSeadragon\n * @see {@link http://www.jquery.com/ jQuery}\n */\n $.isWindow = function( obj ) {\n return obj && typeof obj === \"object\" && \"setInterval\" in obj;\n };\n\n\n /**\n * Taken from jQuery 1.6.1\n * @function type\n * @memberof OpenSeadragon\n * @see {@link http://www.jquery.com/ jQuery}\n */\n $.type = function( obj ) {\n return ( obj === null ) || ( obj === undefined ) ?\n String( obj ) :\n class2type[ toString.call(obj) ] || \"object\";\n };\n\n\n /**\n * Taken from jQuery 1.6.1\n * @function isPlainObject\n * @memberof OpenSeadragon\n * @see {@link http://www.jquery.com/ jQuery}\n */\n $.isPlainObject = function( obj ) {\n // Must be an Object.\n // Because of IE, we also have to check the presence of the constructor property.\n // Make sure that DOM nodes and window objects don't pass through, as well\n if ( !obj || OpenSeadragon.type(obj) !== \"object\" || obj.nodeType || $.isWindow( obj ) ) {\n return false;\n }\n\n // Not own constructor property must be Object\n if ( obj.constructor &&\n !hasOwn.call(obj, \"constructor\") &&\n !hasOwn.call(obj.constructor.prototype, \"isPrototypeOf\") ) {\n return false;\n }\n\n // Own properties are enumerated firstly, so to speed up,\n // if last one is own, then all properties are own.\n\n var lastKey;\n for (var key in obj ) {\n lastKey = key;\n }\n\n return lastKey === undefined || hasOwn.call( obj, lastKey );\n };\n\n\n /**\n * Taken from jQuery 1.6.1\n * @function isEmptyObject\n * @memberof OpenSeadragon\n * @see {@link http://www.jquery.com/ jQuery}\n */\n $.isEmptyObject = function( obj ) {\n for ( var name in obj ) {\n return false;\n }\n return true;\n };\n\n /**\n * Shim around Object.freeze. Does nothing if Object.freeze is not supported.\n * @param {Object} obj The object to freeze.\n * @return {Object} obj The frozen object.\n */\n $.freezeObject = function(obj) {\n if (Object.freeze) {\n $.freezeObject = Object.freeze;\n } else {\n $.freezeObject = function(obj) {\n return obj;\n };\n }\n return $.freezeObject(obj);\n };\n\n /**\n * True if the browser supports the HTML5 canvas element\n * @member {Boolean} supportsCanvas\n * @memberof OpenSeadragon\n */\n $.supportsCanvas = (function () {\n var canvasElement = document.createElement( 'canvas' );\n return !!( $.isFunction( canvasElement.getContext ) &&\n canvasElement.getContext( '2d' ) );\n }());\n\n /**\n * Test whether the submitted canvas is tainted or not.\n * @argument {Canvas} canvas The canvas to test.\n * @returns {Boolean} True if the canvas is tainted.\n */\n $.isCanvasTainted = function(canvas) {\n var isTainted = false;\n try {\n // We test if the canvas is tainted by retrieving data from it.\n // An exception will be raised if the canvas is tainted.\n canvas.getContext('2d').getImageData(0, 0, 1, 1);\n } catch (e) {\n isTainted = true;\n }\n return isTainted;\n };\n\n /**\n * A ratio comparing the device screen's pixel density to the canvas's backing store pixel density,\n * clamped to a minimum of 1. Defaults to 1 if canvas isn't supported by the browser.\n * @member {Number} pixelDensityRatio\n * @memberof OpenSeadragon\n */\n $.pixelDensityRatio = (function () {\n if ( $.supportsCanvas ) {\n var context = document.createElement('canvas').getContext('2d');\n var devicePixelRatio = window.devicePixelRatio || 1;\n var backingStoreRatio = context.webkitBackingStorePixelRatio ||\n context.mozBackingStorePixelRatio ||\n context.msBackingStorePixelRatio ||\n context.oBackingStorePixelRatio ||\n context.backingStorePixelRatio || 1;\n return Math.max(devicePixelRatio, 1) / backingStoreRatio;\n } else {\n return 1;\n }\n }());\n\n}( OpenSeadragon ));\n\n/**\n * This closure defines all static methods available to the OpenSeadragon\n * namespace. Many, if not most, are taked directly from jQuery for use\n * to simplify and reduce common programming patterns. More static methods\n * from jQuery may eventually make their way into this though we are\n * attempting to avoid an explicit dependency on jQuery only because\n * OpenSeadragon is a broadly useful code base and would be made less broad\n * by requiring jQuery fully.\n *\n * Some static methods have also been refactored from the original OpenSeadragon\n * project.\n */\n(function( $ ){\n\n /**\n * Taken from jQuery 1.6.1\n * @function extend\n * @memberof OpenSeadragon\n * @see {@link http://www.jquery.com/ jQuery}\n */\n $.extend = function() {\n var options,\n name,\n src,\n copy,\n copyIsArray,\n clone,\n target = arguments[ 0 ] || {},\n length = arguments.length,\n deep = false,\n i = 1;\n\n // Handle a deep copy situation\n if ( typeof target === \"boolean\" ) {\n deep = target;\n target = arguments[ 1 ] || {};\n // skip the boolean and the target\n i = 2;\n }\n\n // Handle case when target is a string or something (possible in deep copy)\n if ( typeof target !== \"object\" && !OpenSeadragon.isFunction( target ) ) {\n target = {};\n }\n\n // extend jQuery itself if only one argument is passed\n if ( length === i ) {\n target = this;\n --i;\n }\n\n for ( ; i < length; i++ ) {\n // Only deal with non-null/undefined values\n options = arguments[ i ];\n if ( options !== null || options !== undefined ) {\n // Extend the base object\n for ( name in options ) {\n src = target[ name ];\n copy = options[ name ];\n\n // Prevent never-ending loop\n if ( target === copy ) {\n continue;\n }\n\n // Recurse if we're merging plain objects or arrays\n if ( deep && copy && ( OpenSeadragon.isPlainObject( copy ) || ( copyIsArray = OpenSeadragon.isArray( copy ) ) ) ) {\n if ( copyIsArray ) {\n copyIsArray = false;\n clone = src && OpenSeadragon.isArray( src ) ? src : [];\n\n } else {\n clone = src && OpenSeadragon.isPlainObject( src ) ? src : {};\n }\n\n // Never move original objects, clone them\n target[ name ] = OpenSeadragon.extend( deep, clone, copy );\n\n // Don't bring in undefined values\n } else if ( copy !== undefined ) {\n target[ name ] = copy;\n }\n }\n }\n }\n\n // Return the modified object\n return target;\n };\n\n var isIOSDevice = function () {\n if (typeof navigator !== 'object') {\n return false;\n }\n var userAgent = navigator.userAgent;\n if (typeof userAgent !== 'string') {\n return false;\n }\n return userAgent.indexOf('iPhone') !== -1 ||\n userAgent.indexOf('iPad') !== -1 ||\n userAgent.indexOf('iPod') !== -1;\n };\n\n $.extend( $, /** @lends OpenSeadragon */{\n /**\n * The default values for the optional settings documented at {@link OpenSeadragon.Options}.\n * @static\n * @type {Object}\n */\n DEFAULT_SETTINGS: {\n //DATA SOURCE DETAILS\n xmlPath: null,\n tileSources: null,\n tileHost: null,\n initialPage: 0,\n crossOriginPolicy: false,\n ajaxWithCredentials: false,\n loadTilesWithAjax: false,\n ajaxHeaders: {},\n\n //PAN AND ZOOM SETTINGS AND CONSTRAINTS\n panHorizontal: true,\n panVertical: true,\n constrainDuringPan: false,\n wrapHorizontal: false,\n wrapVertical: false,\n visibilityRatio: 0.5, //-> how much of the viewer can be negative space\n minPixelRatio: 0.5, //->closer to 0 draws tiles meant for a higher zoom at this zoom\n defaultZoomLevel: 0,\n minZoomLevel: null,\n maxZoomLevel: null,\n homeFillsViewer: false,\n\n //UI RESPONSIVENESS AND FEEL\n clickTimeThreshold: 300,\n clickDistThreshold: 5,\n dblClickTimeThreshold: 300,\n dblClickDistThreshold: 20,\n springStiffness: 6.5,\n animationTime: 1.2,\n gestureSettingsMouse: {\n scrollToZoom: true,\n clickToZoom: true,\n dblClickToZoom: false,\n pinchToZoom: false,\n flickEnabled: false,\n flickMinSpeed: 120,\n flickMomentum: 0.25,\n pinchRotate: false\n },\n gestureSettingsTouch: {\n scrollToZoom: false,\n clickToZoom: false,\n dblClickToZoom: true,\n pinchToZoom: true,\n flickEnabled: true,\n flickMinSpeed: 120,\n flickMomentum: 0.25,\n pinchRotate: false\n },\n gestureSettingsPen: {\n scrollToZoom: false,\n clickToZoom: true,\n dblClickToZoom: false,\n pinchToZoom: false,\n flickEnabled: false,\n flickMinSpeed: 120,\n flickMomentum: 0.25,\n pinchRotate: false\n },\n gestureSettingsUnknown: {\n scrollToZoom: false,\n clickToZoom: false,\n dblClickToZoom: true,\n pinchToZoom: true,\n flickEnabled: true,\n flickMinSpeed: 120,\n flickMomentum: 0.25,\n pinchRotate: false\n },\n zoomPerClick: 2,\n zoomPerScroll: 1.2,\n zoomPerSecond: 1.0,\n blendTime: 0,\n alwaysBlend: false,\n autoHideControls: true,\n immediateRender: false,\n minZoomImageRatio: 0.9, //-> closer to 0 allows zoom out to infinity\n maxZoomPixelRatio: 1.1, //-> higher allows 'over zoom' into pixels\n smoothTileEdgesMinZoom: 1.1, //-> higher than maxZoomPixelRatio disables it\n iOSDevice: isIOSDevice(),\n pixelsPerWheelLine: 40,\n autoResize: true,\n preserveImageSizeOnResize: false, // requires autoResize=true\n minScrollDeltaTime: 50,\n\n //DEFAULT CONTROL SETTINGS\n showSequenceControl: true, //SEQUENCE\n sequenceControlAnchor: null, //SEQUENCE\n preserveViewport: false, //SEQUENCE\n preserveOverlays: false, //SEQUENCE\n navPrevNextWrap: false, //SEQUENCE\n showNavigationControl: true, //ZOOM/HOME/FULL/ROTATION\n navigationControlAnchor: null, //ZOOM/HOME/FULL/ROTATION\n showZoomControl: true, //ZOOM\n showHomeControl: true, //HOME\n showFullPageControl: true, //FULL\n showRotationControl: false, //ROTATION\n controlsFadeDelay: 2000, //ZOOM/HOME/FULL/SEQUENCE\n controlsFadeLength: 1500, //ZOOM/HOME/FULL/SEQUENCE\n mouseNavEnabled: true, //GENERAL MOUSE INTERACTIVITY\n\n //VIEWPORT NAVIGATOR SETTINGS\n showNavigator: false,\n navigatorId: null,\n navigatorPosition: null,\n navigatorSizeRatio: 0.2,\n navigatorMaintainSizeRatio: false,\n navigatorTop: null,\n navigatorLeft: null,\n navigatorHeight: null,\n navigatorWidth: null,\n navigatorAutoResize: true,\n navigatorAutoFade: true,\n navigatorRotate: true,\n\n // INITIAL ROTATION\n degrees: 0,\n\n // APPEARANCE\n opacity: 1,\n preload: false,\n compositeOperation: null,\n placeholderFillStyle: null,\n\n //REFERENCE STRIP SETTINGS\n showReferenceStrip: false,\n referenceStripScroll: 'horizontal',\n referenceStripElement: null,\n referenceStripHeight: null,\n referenceStripWidth: null,\n referenceStripPosition: 'BOTTOM_LEFT',\n referenceStripSizeRatio: 0.2,\n\n //COLLECTION VISUALIZATION SETTINGS\n collectionRows: 3, //or columns depending on layout\n collectionColumns: 0, //columns in horizontal layout, rows in vertical layout\n collectionLayout: 'horizontal', //vertical\n collectionMode: false,\n collectionTileSize: 800,\n collectionTileMargin: 80,\n\n //PERFORMANCE SETTINGS\n imageLoaderLimit: 0,\n maxImageCacheCount: 200,\n timeout: 30000,\n useCanvas: true, // Use canvas element for drawing if available\n\n //INTERFACE RESOURCE SETTINGS\n prefixUrl: \"/images/\",\n navImages: {\n zoomIn: {\n REST: 'zoomin_rest.png',\n GROUP: 'zoomin_grouphover.png',\n HOVER: 'zoomin_hover.png',\n DOWN: 'zoomin_pressed.png'\n },\n zoomOut: {\n REST: 'zoomout_rest.png',\n GROUP: 'zoomout_grouphover.png',\n HOVER: 'zoomout_hover.png',\n DOWN: 'zoomout_pressed.png'\n },\n home: {\n REST: 'home_rest.png',\n GROUP: 'home_grouphover.png',\n HOVER: 'home_hover.png',\n DOWN: 'home_pressed.png'\n },\n fullpage: {\n REST: 'fullpage_rest.png',\n GROUP: 'fullpage_grouphover.png',\n HOVER: 'fullpage_hover.png',\n DOWN: 'fullpage_pressed.png'\n },\n rotateleft: {\n REST: 'rotateleft_rest.png',\n GROUP: 'rotateleft_grouphover.png',\n HOVER: 'rotateleft_hover.png',\n DOWN: 'rotateleft_pressed.png'\n },\n rotateright: {\n REST: 'rotateright_rest.png',\n GROUP: 'rotateright_grouphover.png',\n HOVER: 'rotateright_hover.png',\n DOWN: 'rotateright_pressed.png'\n },\n previous: {\n REST: 'previous_rest.png',\n GROUP: 'previous_grouphover.png',\n HOVER: 'previous_hover.png',\n DOWN: 'previous_pressed.png'\n },\n next: {\n REST: 'next_rest.png',\n GROUP: 'next_grouphover.png',\n HOVER: 'next_hover.png',\n DOWN: 'next_pressed.png'\n }\n },\n\n //DEVELOPER SETTINGS\n debugMode: false,\n debugGridColor: ['#437AB2', '#1B9E77', '#D95F02', '#7570B3', '#E7298A', '#66A61E', '#E6AB02', '#A6761D', '#666666']\n },\n\n\n /**\n * TODO: get rid of this. I can't see how it's required at all. Looks\n * like an early legacy code artifact.\n * @static\n * @ignore\n */\n SIGNAL: \"----seadragon----\",\n\n\n /**\n * Returns a function which invokes the method as if it were a method belonging to the object.\n * @function\n * @param {Object} object\n * @param {Function} method\n * @returns {Function}\n */\n delegate: function( object, method ) {\n return function(){\n var args = arguments;\n if ( args === undefined ){\n args = [];\n }\n return method.apply( object, args );\n };\n },\n\n\n /**\n * An enumeration of Browser vendors.\n * @static\n * @type {Object}\n * @property {Number} UNKNOWN\n * @property {Number} IE\n * @property {Number} FIREFOX\n * @property {Number} SAFARI\n * @property {Number} CHROME\n * @property {Number} OPERA\n */\n BROWSERS: {\n UNKNOWN: 0,\n IE: 1,\n FIREFOX: 2,\n SAFARI: 3,\n CHROME: 4,\n OPERA: 5\n },\n\n\n /**\n * Returns a DOM Element for the given id or element.\n * @function\n * @param {String|Element} element Accepts an id or element.\n * @returns {Element} The element with the given id, null, or the element itself.\n */\n getElement: function( element ) {\n if ( typeof ( element ) == \"string\" ) {\n element = document.getElementById( element );\n }\n return element;\n },\n\n\n /**\n * Determines the position of the upper-left corner of the element.\n * @function\n * @param {Element|String} element - the elemenet we want the position for.\n * @returns {OpenSeadragon.Point} - the position of the upper left corner of the element.\n */\n getElementPosition: function( element ) {\n var result = new $.Point(),\n isFixed,\n offsetParent;\n\n element = $.getElement( element );\n isFixed = $.getElementStyle( element ).position == \"fixed\";\n offsetParent = getOffsetParent( element, isFixed );\n\n while ( offsetParent ) {\n\n result.x += element.offsetLeft;\n result.y += element.offsetTop;\n\n if ( isFixed ) {\n result = result.plus( $.getPageScroll() );\n }\n\n element = offsetParent;\n isFixed = $.getElementStyle( element ).position == \"fixed\";\n offsetParent = getOffsetParent( element, isFixed );\n }\n\n return result;\n },\n\n\n /**\n * Determines the position of the upper-left corner of the element adjusted for current page and/or element scroll.\n * @function\n * @param {Element|String} element - the element we want the position for.\n * @returns {OpenSeadragon.Point} - the position of the upper left corner of the element adjusted for current page and/or element scroll.\n */\n getElementOffset: function( element ) {\n element = $.getElement( element );\n\n var doc = element && element.ownerDocument,\n docElement,\n win,\n boundingRect = { top: 0, left: 0 };\n\n if ( !doc ) {\n return new $.Point();\n }\n\n docElement = doc.documentElement;\n\n if ( typeof element.getBoundingClientRect !== typeof undefined ) {\n boundingRect = element.getBoundingClientRect();\n }\n\n win = ( doc == doc.window ) ?\n doc :\n ( doc.nodeType === 9 ) ?\n doc.defaultView || doc.parentWindow :\n false;\n\n return new $.Point(\n boundingRect.left + ( win.pageXOffset || docElement.scrollLeft ) - ( docElement.clientLeft || 0 ),\n boundingRect.top + ( win.pageYOffset || docElement.scrollTop ) - ( docElement.clientTop || 0 )\n );\n },\n\n\n /**\n * Determines the height and width of the given element.\n * @function\n * @param {Element|String} element\n * @returns {OpenSeadragon.Point}\n */\n getElementSize: function( element ) {\n element = $.getElement( element );\n\n return new $.Point(\n element.clientWidth,\n element.clientHeight\n );\n },\n\n\n /**\n * Returns the CSSStyle object for the given element.\n * @function\n * @param {Element|String} element\n * @returns {CSSStyle}\n */\n getElementStyle:\n document.documentElement.currentStyle ?\n function( element ) {\n element = $.getElement( element );\n return element.currentStyle;\n } :\n function( element ) {\n element = $.getElement( element );\n return window.getComputedStyle( element, \"\" );\n },\n\n /**\n * Returns the property with the correct vendor prefix appended.\n * @param {String} property the property name\n * @returns {String} the property with the correct prefix or null if not\n * supported.\n */\n getCssPropertyWithVendorPrefix: function(property) {\n var memo = {};\n\n $.getCssPropertyWithVendorPrefix = function(property) {\n if (memo[property] !== undefined) {\n return memo[property];\n }\n var style = document.createElement('div').style;\n var result = null;\n if (style[property] !== undefined) {\n result = property;\n } else {\n var prefixes = ['Webkit', 'Moz', 'MS', 'O',\n 'webkit', 'moz', 'ms', 'o'];\n var suffix = $.capitalizeFirstLetter(property);\n for (var i = 0; i < prefixes.length; i++) {\n var prop = prefixes[i] + suffix;\n if (style[prop] !== undefined) {\n result = prop;\n break;\n }\n }\n }\n memo[property] = result;\n return result;\n };\n return $.getCssPropertyWithVendorPrefix(property);\n },\n\n /**\n * Capitalizes the first letter of a string\n * @param {String} string\n * @returns {String} The string with the first letter capitalized\n */\n capitalizeFirstLetter: function(string) {\n return string.charAt(0).toUpperCase() + string.slice(1);\n },\n\n /**\n * Compute the modulo of a number but makes sure to always return\n * a positive value.\n * @param {Number} number the number to computes the modulo of\n * @param {Number} modulo the modulo\n * @returns {Number} the result of the modulo of number\n */\n positiveModulo: function(number, modulo) {\n var result = number % modulo;\n if (result < 0) {\n result += modulo;\n }\n return result;\n },\n\n /**\n * Determines if a point is within the bounding rectangle of the given element (hit-test).\n * @function\n * @param {Element|String} element\n * @param {OpenSeadragon.Point} point\n * @returns {Boolean}\n */\n pointInElement: function( element, point ) {\n element = $.getElement( element );\n var offset = $.getElementOffset( element ),\n size = $.getElementSize( element );\n return point.x >= offset.x && point.x < offset.x + size.x && point.y < offset.y + size.y && point.y >= offset.y;\n },\n\n\n /**\n * Gets the latest event, really only useful internally since its\n * specific to IE behavior.\n * @function\n * @param {Event} [event]\n * @returns {Event}\n * @deprecated For internal use only\n * @private\n */\n getEvent: function( event ) {\n if( event ){\n $.getEvent = function( event ) {\n return event;\n };\n } else {\n $.getEvent = function() {\n return window.event;\n };\n }\n return $.getEvent( event );\n },\n\n\n /**\n * Gets the position of the mouse on the screen for a given event.\n * @function\n * @param {Event} [event]\n * @returns {OpenSeadragon.Point}\n */\n getMousePosition: function( event ) {\n\n if ( typeof( event.pageX ) == \"number\" ) {\n $.getMousePosition = function( event ){\n var result = new $.Point();\n\n event = $.getEvent( event );\n result.x = event.pageX;\n result.y = event.pageY;\n\n return result;\n };\n } else if ( typeof( event.clientX ) == \"number\" ) {\n $.getMousePosition = function( event ){\n var result = new $.Point();\n\n event = $.getEvent( event );\n result.x =\n event.clientX +\n document.body.scrollLeft +\n document.documentElement.scrollLeft;\n result.y =\n event.clientY +\n document.body.scrollTop +\n document.documentElement.scrollTop;\n\n return result;\n };\n } else {\n throw new Error(\n \"Unknown event mouse position, no known technique.\"\n );\n }\n\n return $.getMousePosition( event );\n },\n\n\n /**\n * Determines the page's current scroll position.\n * @function\n * @returns {OpenSeadragon.Point}\n */\n getPageScroll: function() {\n var docElement = document.documentElement || {},\n body = document.body || {};\n\n if ( typeof( window.pageXOffset ) == \"number\" ) {\n $.getPageScroll = function(){\n return new $.Point(\n window.pageXOffset,\n window.pageYOffset\n );\n };\n } else if ( body.scrollLeft || body.scrollTop ) {\n $.getPageScroll = function(){\n return new $.Point(\n document.body.scrollLeft,\n document.body.scrollTop\n );\n };\n } else if ( docElement.scrollLeft || docElement.scrollTop ) {\n $.getPageScroll = function(){\n return new $.Point(\n document.documentElement.scrollLeft,\n document.documentElement.scrollTop\n );\n };\n } else {\n // We can't reassign the function yet, as there was no scroll.\n return new $.Point(0, 0);\n }\n\n return $.getPageScroll();\n },\n\n /**\n * Set the page scroll position.\n * @function\n * @returns {OpenSeadragon.Point}\n */\n setPageScroll: function( scroll ) {\n if ( typeof ( window.scrollTo ) !== \"undefined\" ) {\n $.setPageScroll = function( scroll ) {\n window.scrollTo( scroll.x, scroll.y );\n };\n } else {\n var originalScroll = $.getPageScroll();\n if ( originalScroll.x === scroll.x &&\n originalScroll.y === scroll.y ) {\n // We are already correctly positioned and there\n // is no way to detect the correct method.\n return;\n }\n\n document.body.scrollLeft = scroll.x;\n document.body.scrollTop = scroll.y;\n var currentScroll = $.getPageScroll();\n if ( currentScroll.x !== originalScroll.x &&\n currentScroll.y !== originalScroll.y ) {\n $.setPageScroll = function( scroll ) {\n document.body.scrollLeft = scroll.x;\n document.body.scrollTop = scroll.y;\n };\n return;\n }\n\n document.documentElement.scrollLeft = scroll.x;\n document.documentElement.scrollTop = scroll.y;\n currentScroll = $.getPageScroll();\n if ( currentScroll.x !== originalScroll.x &&\n currentScroll.y !== originalScroll.y ) {\n $.setPageScroll = function( scroll ) {\n document.documentElement.scrollLeft = scroll.x;\n document.documentElement.scrollTop = scroll.y;\n };\n return;\n }\n\n // We can't find anything working, so we do nothing.\n $.setPageScroll = function( scroll ) {\n };\n }\n\n return $.setPageScroll( scroll );\n },\n\n /**\n * Determines the size of the browsers window.\n * @function\n * @returns {OpenSeadragon.Point}\n */\n getWindowSize: function() {\n var docElement = document.documentElement || {},\n body = document.body || {};\n\n if ( typeof( window.innerWidth ) == 'number' ) {\n $.getWindowSize = function(){\n return new $.Point(\n window.innerWidth,\n window.innerHeight\n );\n };\n } else if ( docElement.clientWidth || docElement.clientHeight ) {\n $.getWindowSize = function(){\n return new $.Point(\n document.documentElement.clientWidth,\n document.documentElement.clientHeight\n );\n };\n } else if ( body.clientWidth || body.clientHeight ) {\n $.getWindowSize = function(){\n return new $.Point(\n document.body.clientWidth,\n document.body.clientHeight\n );\n };\n } else {\n throw new Error(\"Unknown window size, no known technique.\");\n }\n\n return $.getWindowSize();\n },\n\n\n /**\n * Wraps the given element in a nest of divs so that the element can\n * be easily centered using CSS tables\n * @function\n * @param {Element|String} element\n * @returns {Element} outermost wrapper element\n */\n makeCenteredNode: function( element ) {\n // Convert a possible ID to an actual HTMLElement\n element = $.getElement( element );\n\n /*\n CSS tables require you to have a display:table/row/cell hierarchy so we need to create\n three nested wrapper divs:\n */\n\n var wrappers = [\n $.makeNeutralElement( 'div' ),\n $.makeNeutralElement( 'div' ),\n $.makeNeutralElement( 'div' )\n ];\n\n // It feels like we should be able to pass style dicts to makeNeutralElement:\n $.extend(wrappers[0].style, {\n display: \"table\",\n height: \"100%\",\n width: \"100%\"\n });\n\n $.extend(wrappers[1].style, {\n display: \"table-row\"\n });\n\n $.extend(wrappers[2].style, {\n display: \"table-cell\",\n verticalAlign: \"middle\",\n textAlign: \"center\"\n });\n\n wrappers[0].appendChild(wrappers[1]);\n wrappers[1].appendChild(wrappers[2]);\n wrappers[2].appendChild(element);\n\n return wrappers[0];\n },\n\n\n /**\n * Creates an easily positionable element of the given type that therefor\n * serves as an excellent container element.\n * @function\n * @param {String} tagName\n * @returns {Element}\n */\n makeNeutralElement: function( tagName ) {\n var element = document.createElement( tagName ),\n style = element.style;\n\n style.background = \"transparent none\";\n style.border = \"none\";\n style.margin = \"0px\";\n style.padding = \"0px\";\n style.position = \"static\";\n\n return element;\n },\n\n\n /**\n * Returns the current milliseconds, using Date.now() if available\n * @function\n */\n now: function( ) {\n if (Date.now) {\n $.now = Date.now;\n } else {\n $.now = function() {\n return new Date().getTime();\n };\n }\n\n return $.now();\n },\n\n\n /**\n * Ensures an image is loaded correctly to support alpha transparency.\n * Generally only IE has issues doing this correctly for formats like\n * png.\n * @function\n * @param {String} src\n * @returns {Element}\n */\n makeTransparentImage: function( src ) {\n\n $.makeTransparentImage = function( src ){\n var img = $.makeNeutralElement( \"img\" );\n\n img.src = src;\n\n return img;\n };\n\n if ( $.Browser.vendor == $.BROWSERS.IE && $.Browser.version < 7 ) {\n\n $.makeTransparentImage = function( src ){\n var img = $.makeNeutralElement( \"img\" ),\n element = null;\n\n element = $.makeNeutralElement(\"span\");\n element.style.display = \"inline-block\";\n\n img.onload = function() {\n element.style.width = element.style.width || img.width + \"px\";\n element.style.height = element.style.height || img.height + \"px\";\n\n img.onload = null;\n img = null; // to prevent memory leaks in IE\n };\n\n img.src = src;\n element.style.filter =\n \"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='\" +\n src +\n \"', sizingMethod='scale')\";\n\n return element;\n };\n\n }\n\n return $.makeTransparentImage( src );\n },\n\n\n /**\n * Sets the opacity of the specified element.\n * @function\n * @param {Element|String} element\n * @param {Number} opacity\n * @param {Boolean} [usesAlpha]\n */\n setElementOpacity: function( element, opacity, usesAlpha ) {\n\n var ieOpacity,\n ieFilter;\n\n element = $.getElement( element );\n\n if ( usesAlpha && !$.Browser.alpha ) {\n opacity = Math.round( opacity );\n }\n\n if ( $.Browser.opacity ) {\n element.style.opacity = opacity < 1 ? opacity : \"\";\n } else {\n if ( opacity < 1 ) {\n ieOpacity = Math.round( 100 * opacity );\n ieFilter = \"alpha(opacity=\" + ieOpacity + \")\";\n element.style.filter = ieFilter;\n } else {\n element.style.filter = \"\";\n }\n }\n },\n\n\n /**\n * Sets the specified element's touch-action style attribute to 'none'.\n * @function\n * @param {Element|String} element\n */\n setElementTouchActionNone: function( element ) {\n element = $.getElement( element );\n if ( typeof element.style.touchAction !== 'undefined' ) {\n element.style.touchAction = 'none';\n } else if ( typeof element.style.msTouchAction !== 'undefined' ) {\n element.style.msTouchAction = 'none';\n }\n },\n\n\n /**\n * Add the specified CSS class to the element if not present.\n * @function\n * @param {Element|String} element\n * @param {String} className\n */\n addClass: function( element, className ) {\n element = $.getElement( element );\n\n if (!element.className) {\n element.className = className;\n } else if ( ( ' ' + element.className + ' ' ).\n indexOf( ' ' + className + ' ' ) === -1 ) {\n element.className += ' ' + className;\n }\n },\n\n /**\n * Find the first index at which an element is found in an array or -1\n * if not present.\n *\n * Code taken and adapted from\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf#Compatibility\n *\n * @function\n * @param {Array} array The array from which to find the element\n * @param {Object} searchElement The element to find\n * @param {Number} [fromIndex=0] Index to start research.\n * @returns {Number} The index of the element in the array.\n */\n indexOf: function( array, searchElement, fromIndex ) {\n if ( Array.prototype.indexOf ) {\n this.indexOf = function( array, searchElement, fromIndex ) {\n return array.indexOf( searchElement, fromIndex );\n };\n } else {\n this.indexOf = function( array, searchElement, fromIndex ) {\n var i,\n pivot = ( fromIndex ) ? fromIndex : 0,\n length;\n if ( !array ) {\n throw new TypeError( );\n }\n\n length = array.length;\n if ( length === 0 || pivot >= length ) {\n return -1;\n }\n\n if ( pivot < 0 ) {\n pivot = length - Math.abs( pivot );\n }\n\n for ( i = pivot; i < length; i++ ) {\n if ( array[i] === searchElement ) {\n return i;\n }\n }\n return -1;\n };\n }\n return this.indexOf( array, searchElement, fromIndex );\n },\n\n /**\n * Remove the specified CSS class from the element.\n * @function\n * @param {Element|String} element\n * @param {String} className\n */\n removeClass: function( element, className ) {\n var oldClasses,\n newClasses = [],\n i;\n\n element = $.getElement( element );\n oldClasses = element.className.split( /\\s+/ );\n for ( i = 0; i < oldClasses.length; i++ ) {\n if ( oldClasses[ i ] && oldClasses[ i ] !== className ) {\n newClasses.push( oldClasses[ i ] );\n }\n }\n element.className = newClasses.join(' ');\n },\n\n\n /**\n * Adds an event listener for the given element, eventName and handler.\n * @function\n * @param {Element|String} element\n * @param {String} eventName\n * @param {Function} handler\n * @param {Boolean} [useCapture]\n */\n addEvent: (function () {\n if ( window.addEventListener ) {\n return function ( element, eventName, handler, useCapture ) {\n element = $.getElement( element );\n element.addEventListener( eventName, handler, useCapture );\n };\n } else if ( window.attachEvent ) {\n return function ( element, eventName, handler, useCapture ) {\n element = $.getElement( element );\n element.attachEvent( 'on' + eventName, handler );\n };\n } else {\n throw new Error( \"No known event model.\" );\n }\n }()),\n\n\n /**\n * Remove a given event listener for the given element, event type and\n * handler.\n * @function\n * @param {Element|String} element\n * @param {String} eventName\n * @param {Function} handler\n * @param {Boolean} [useCapture]\n */\n removeEvent: (function () {\n if ( window.removeEventListener ) {\n return function ( element, eventName, handler, useCapture ) {\n element = $.getElement( element );\n element.removeEventListener( eventName, handler, useCapture );\n };\n } else if ( window.detachEvent ) {\n return function( element, eventName, handler, useCapture ) {\n element = $.getElement( element );\n element.detachEvent( 'on' + eventName, handler );\n };\n } else {\n throw new Error( \"No known event model.\" );\n }\n }()),\n\n\n /**\n * Cancels the default browser behavior had the event propagated all\n * the way up the DOM to the window object.\n * @function\n * @param {Event} [event]\n */\n cancelEvent: function( event ) {\n event = $.getEvent( event );\n\n if ( event.preventDefault ) {\n $.cancelEvent = function( event ){\n // W3C for preventing default\n event.preventDefault();\n };\n } else {\n $.cancelEvent = function( event ){\n event = $.getEvent( event );\n // legacy for preventing default\n event.cancel = true;\n // IE for preventing default\n event.returnValue = false;\n };\n }\n $.cancelEvent( event );\n },\n\n\n /**\n * Stops the propagation of the event up the DOM.\n * @function\n * @param {Event} [event]\n */\n stopEvent: function( event ) {\n event = $.getEvent( event );\n\n if ( event.stopPropagation ) {\n // W3C for stopping propagation\n $.stopEvent = function( event ){\n event.stopPropagation();\n };\n } else {\n // IE for stopping propagation\n $.stopEvent = function( event ){\n event = $.getEvent( event );\n event.cancelBubble = true;\n };\n\n }\n\n $.stopEvent( event );\n },\n\n\n /**\n * Similar to OpenSeadragon.delegate, but it does not immediately call\n * the method on the object, returning a function which can be called\n * repeatedly to delegate the method. It also allows additonal arguments\n * to be passed during construction which will be added during each\n * invocation, and each invocation can add additional arguments as well.\n *\n * @function\n * @param {Object} object\n * @param {Function} method\n * @param [args] any additional arguments are passed as arguments to the\n * created callback\n * @returns {Function}\n */\n createCallback: function( object, method ) {\n //TODO: This pattern is painful to use and debug. It's much cleaner\n // to use pinning plus anonymous functions. Get rid of this\n // pattern!\n var initialArgs = [],\n i;\n for ( i = 2; i < arguments.length; i++ ) {\n initialArgs.push( arguments[ i ] );\n }\n\n return function() {\n var args = initialArgs.concat( [] ),\n i;\n for ( i = 0; i < arguments.length; i++ ) {\n args.push( arguments[ i ] );\n }\n\n return method.apply( object, args );\n };\n },\n\n\n /**\n * Retreives the value of a url parameter from the window.location string.\n * @function\n * @param {String} key\n * @returns {String} The value of the url parameter or null if no param matches.\n */\n getUrlParameter: function( key ) {\n // eslint-disable-next-line no-use-before-define\n var value = URLPARAMS[ key ];\n return value ? value : null;\n },\n\n /**\n * Retrieves the protocol used by the url. The url can either be absolute\n * or relative.\n * @function\n * @private\n * @param {String} url The url to retrieve the protocol from.\n * @return {String} The protocol (http:, https:, file:, ftp: ...)\n */\n getUrlProtocol: function( url ) {\n var match = url.match(/^([a-z]+:)\\/\\//i);\n if ( match === null ) {\n // Relative URL, retrive the protocol from window.location\n return window.location.protocol;\n }\n return match[1].toLowerCase();\n },\n\n /**\n * Create an XHR object\n * @private\n * @param {type} [local] If set to true, the XHR will be file: protocol\n * compatible if possible (but may raise a warning in the browser).\n * @returns {XMLHttpRequest}\n */\n createAjaxRequest: function( local ) {\n // IE11 does not support window.ActiveXObject so we just try to\n // create one to see if it is supported.\n // See: http://msdn.microsoft.com/en-us/library/ie/dn423948%28v=vs.85%29.aspx\n var supportActiveX;\n try {\n /* global ActiveXObject:true */\n supportActiveX = !!new ActiveXObject( \"Microsoft.XMLHTTP\" );\n } catch( e ) {\n supportActiveX = false;\n }\n\n if ( supportActiveX ) {\n if ( window.XMLHttpRequest ) {\n $.createAjaxRequest = function( local ) {\n if ( local ) {\n return new ActiveXObject( \"Microsoft.XMLHTTP\" );\n }\n return new XMLHttpRequest();\n };\n } else {\n $.createAjaxRequest = function() {\n return new ActiveXObject( \"Microsoft.XMLHTTP\" );\n };\n }\n } else if ( window.XMLHttpRequest ) {\n $.createAjaxRequest = function() {\n return new XMLHttpRequest();\n };\n } else {\n throw new Error( \"Browser doesn't support XMLHttpRequest.\" );\n }\n return $.createAjaxRequest( local );\n },\n\n /**\n * Makes an AJAX request.\n * @param {Object} options\n * @param {String} options.url - the url to request\n * @param {Function} options.success - a function to call on a successful response\n * @param {Function} options.error - a function to call on when an error occurs\n * @param {Object} options.headers - headers to add to the AJAX request\n * @param {String} options.responseType - the response type of the the AJAX request\n * @param {Boolean} [options.withCredentials=false] - whether to set the XHR's withCredentials\n * @throws {Error}\n * @returns {XMLHttpRequest}\n */\n makeAjaxRequest: function( url, onSuccess, onError ) {\n var withCredentials;\n var headers;\n var responseType;\n\n // Note that our preferred API is that you pass in a single object; the named\n // arguments are for legacy support.\n if( $.isPlainObject( url ) ){\n onSuccess = url.success;\n onError = url.error;\n withCredentials = url.withCredentials;\n headers = url.headers;\n responseType = url.responseType || null;\n url = url.url;\n }\n\n var protocol = $.getUrlProtocol( url );\n var request = $.createAjaxRequest( protocol === \"file:\" );\n\n if ( !$.isFunction( onSuccess ) ) {\n throw new Error( \"makeAjaxRequest requires a success callback\" );\n }\n\n request.onreadystatechange = function() {\n // 4 = DONE (https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#Properties)\n if ( request.readyState == 4 ) {\n request.onreadystatechange = function(){};\n\n // With protocols other than http/https, a successful request status is in\n // the 200's on Firefox and 0 on other browsers\n if ( (request.status >= 200 && request.status < 300) ||\n ( request.status === 0 &&\n protocol !== \"http:\" &&\n protocol !== \"https:\" )) {\n onSuccess( request );\n } else {\n $.console.log( \"AJAX request returned %d: %s\", request.status, url );\n\n if ( $.isFunction( onError ) ) {\n onError( request );\n }\n }\n }\n };\n\n try {\n request.open( \"GET\", url, true );\n\n if (responseType) {\n request.responseType = responseType;\n }\n\n if (headers) {\n for (var headerName in headers) {\n if (headers.hasOwnProperty(headerName) && headers[headerName]) {\n request.setRequestHeader(headerName, headers[headerName]);\n }\n }\n }\n\n if (withCredentials) {\n request.withCredentials = true;\n }\n\n request.send(null);\n } catch (e) {\n var msg = e.message;\n\n /*\n IE < 10 does not support CORS and an XHR request to a different origin will fail as soon\n as send() is called. This is particularly easy to miss during development and appear in\n production if you use a CDN or domain sharding and the security policy is likely to break\n exception handlers since any attempt to access a property of the request object will\n raise an access denied TypeError inside the catch block.\n\n To be friendlier, we'll check for this specific error and add a documentation pointer\n to point developers in the right direction. We test the exception number because IE's\n error messages are localized.\n */\n var oldIE = $.Browser.vendor == $.BROWSERS.IE && $.Browser.version < 10;\n if ( oldIE && typeof( e.number ) != \"undefined\" && e.number == -2147024891 ) {\n msg += \"\\nSee http://msdn.microsoft.com/en-us/library/ms537505(v=vs.85).aspx#xdomain\";\n }\n\n $.console.log( \"%s while making AJAX request: %s\", e.name, msg );\n\n request.onreadystatechange = function(){};\n\n if (window.XDomainRequest) { // IE9 or IE8 might as well try to use XDomainRequest\n var xdr = new XDomainRequest();\n if (xdr) {\n xdr.onload = function (e) {\n if ( $.isFunction( onSuccess ) ) {\n onSuccess({ // Faking an xhr object\n responseText: xdr.responseText,\n status: 200, // XDomainRequest doesn't support status codes, so we just fake one! :/\n statusText: 'OK'\n });\n }\n };\n xdr.onerror = function (e) {\n if ($.isFunction(onError)) {\n onError({ // Faking an xhr object\n responseText: xdr.responseText,\n status: 444, // 444 No Response\n statusText: 'An error happened. Due to an XDomainRequest deficiency we can not extract any information about this error. Upgrade your browser.'\n });\n }\n };\n try {\n xdr.open('GET', url);\n xdr.send();\n } catch (e2) {\n if ( $.isFunction( onError ) ) {\n onError( request, e );\n }\n }\n }\n } else {\n if ( $.isFunction( onError ) ) {\n onError( request, e );\n }\n }\n }\n\n return request;\n },\n\n /**\n * Taken from jQuery 1.6.1\n * @function\n * @param {Object} options\n * @param {String} options.url\n * @param {Function} options.callback\n * @param {String} [options.param='callback'] The name of the url parameter\n * to request the jsonp provider with.\n * @param {String} [options.callbackName=] The name of the callback to\n * request the jsonp provider with.\n */\n jsonp: function( options ){\n var script,\n url = options.url,\n head = document.head ||\n document.getElementsByTagName( \"head\" )[ 0 ] ||\n document.documentElement,\n jsonpCallback = options.callbackName || 'openseadragon' + $.now(),\n previous = window[ jsonpCallback ],\n replace = \"$1\" + jsonpCallback + \"$2\",\n callbackParam = options.param || 'callback',\n callback = options.callback;\n\n url = url.replace( /(\\=)\\?(&|$)|\\?\\?/i, replace );\n // Add callback manually\n url += (/\\?/.test( url ) ? \"&\" : \"?\") + callbackParam + \"=\" + jsonpCallback;\n\n // Install callback\n window[ jsonpCallback ] = function( response ) {\n if ( !previous ){\n try{\n delete window[ jsonpCallback ];\n }catch(e){\n //swallow\n }\n } else {\n window[ jsonpCallback ] = previous;\n }\n if( callback && $.isFunction( callback ) ){\n callback( response );\n }\n };\n\n script = document.createElement( \"script\" );\n\n //TODO: having an issue with async info requests\n if( undefined !== options.async || false !== options.async ){\n script.async = \"async\";\n }\n\n if ( options.scriptCharset ) {\n script.charset = options.scriptCharset;\n }\n\n script.src = url;\n\n // Attach handlers for all browsers\n script.onload = script.onreadystatechange = function( _, isAbort ) {\n\n if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {\n\n // Handle memory leak in IE\n script.onload = script.onreadystatechange = null;\n\n // Remove the script\n if ( head && script.parentNode ) {\n head.removeChild( script );\n }\n\n // Dereference the script\n script = undefined;\n }\n };\n // Use insertBefore instead of appendChild to circumvent an IE6 bug.\n // This arises when a base node is used (#2709 and #4378).\n head.insertBefore( script, head.firstChild );\n\n },\n\n\n /**\n * Fully deprecated. Will throw an error.\n * @function\n * @deprecated use {@link OpenSeadragon.Viewer#open}\n */\n createFromDZI: function() {\n throw \"OpenSeadragon.createFromDZI is deprecated, use Viewer.open.\";\n },\n\n /**\n * Parses an XML string into a DOM Document.\n * @function\n * @param {String} string\n * @returns {Document}\n */\n parseXml: function( string ) {\n if ( window.DOMParser ) {\n\n $.parseXml = function( string ) {\n var xmlDoc = null,\n parser;\n\n parser = new DOMParser();\n xmlDoc = parser.parseFromString( string, \"text/xml\" );\n return xmlDoc;\n };\n\n } else if ( window.ActiveXObject ) {\n\n $.parseXml = function( string ) {\n var xmlDoc = null;\n\n xmlDoc = new ActiveXObject( \"Microsoft.XMLDOM\" );\n xmlDoc.async = false;\n xmlDoc.loadXML( string );\n return xmlDoc;\n };\n\n } else {\n throw new Error( \"Browser doesn't support XML DOM.\" );\n }\n\n return $.parseXml( string );\n },\n\n /**\n * Parses a JSON string into a Javascript object.\n * @function\n * @param {String} string\n * @returns {Object}\n */\n parseJSON: function(string) {\n if (window.JSON && window.JSON.parse) {\n $.parseJSON = window.JSON.parse;\n } else {\n // Should only be used by IE8 in non standards mode\n $.parseJSON = function(string) {\n /*jshint evil:true*/\n //eslint-disable-next-line no-eval\n return eval('(' + string + ')');\n };\n }\n return $.parseJSON(string);\n },\n\n /**\n * Reports whether the image format is supported for tiling in this\n * version.\n * @function\n * @param {String} [extension]\n * @returns {Boolean}\n */\n imageFormatSupported: function( extension ) {\n extension = extension ? extension : \"\";\n // eslint-disable-next-line no-use-before-define\n return !!FILEFORMATS[ extension.toLowerCase() ];\n }\n\n });\n\n\n /**\n * The current browser vendor, version, and related information regarding detected features.\n * @member {Object} Browser\n * @memberof OpenSeadragon\n * @static\n * @type {Object}\n * @property {OpenSeadragon.BROWSERS} vendor - One of the {@link OpenSeadragon.BROWSERS} enumeration values.\n * @property {Number} version\n * @property {Boolean} alpha - Does the browser support image alpha transparency.\n */\n $.Browser = {\n vendor: $.BROWSERS.UNKNOWN,\n version: 0,\n alpha: true\n };\n\n\n var FILEFORMATS = {\n \"bmp\": false,\n \"jpeg\": true,\n \"jpg\": true,\n \"png\": true,\n \"tif\": false,\n \"wdp\": false\n },\n URLPARAMS = {};\n\n (function() {\n //A small auto-executing routine to determine the browser vendor,\n //version and supporting feature sets.\n var ver = navigator.appVersion,\n ua = navigator.userAgent,\n regex;\n\n //console.error( 'appName: ' + navigator.appName );\n //console.error( 'appVersion: ' + navigator.appVersion );\n //console.error( 'userAgent: ' + navigator.userAgent );\n\n switch( navigator.appName ){\n case \"Microsoft Internet Explorer\":\n if( !!window.attachEvent &&\n !!window.ActiveXObject ) {\n\n $.Browser.vendor = $.BROWSERS.IE;\n $.Browser.version = parseFloat(\n ua.substring(\n ua.indexOf( \"MSIE\" ) + 5,\n ua.indexOf( \";\", ua.indexOf( \"MSIE\" ) ) )\n );\n }\n break;\n case \"Netscape\":\n if (window.addEventListener) {\n if ( ua.indexOf( \"Firefox\" ) >= 0 ) {\n $.Browser.vendor = $.BROWSERS.FIREFOX;\n $.Browser.version = parseFloat(\n ua.substring( ua.indexOf( \"Firefox\" ) + 8 )\n );\n } else if ( ua.indexOf( \"Safari\" ) >= 0 ) {\n $.Browser.vendor = ua.indexOf( \"Chrome\" ) >= 0 ?\n $.BROWSERS.CHROME :\n $.BROWSERS.SAFARI;\n $.Browser.version = parseFloat(\n ua.substring(\n ua.substring( 0, ua.indexOf( \"Safari\" ) ).lastIndexOf( \"/\" ) + 1,\n ua.indexOf( \"Safari\" )\n )\n );\n } else {\n regex = new RegExp( \"Trident/.*rv:([0-9]{1,}[.0-9]{0,})\");\n if ( regex.exec( ua ) !== null ) {\n $.Browser.vendor = $.BROWSERS.IE;\n $.Browser.version = parseFloat( RegExp.$1 );\n }\n }\n }\n break;\n case \"Opera\":\n $.Browser.vendor = $.BROWSERS.OPERA;\n $.Browser.version = parseFloat( ver );\n break;\n }\n\n // ignore '?' portion of query string\n var query = window.location.search.substring( 1 ),\n parts = query.split('&'),\n part,\n sep,\n i;\n\n for ( i = 0; i < parts.length; i++ ) {\n part = parts[ i ];\n sep = part.indexOf( '=' );\n\n if ( sep > 0 ) {\n URLPARAMS[ part.substring( 0, sep ) ] =\n decodeURIComponent( part.substring( sep + 1 ) );\n }\n }\n\n //determine if this browser supports image alpha transparency\n $.Browser.alpha = !(\n (\n $.Browser.vendor == $.BROWSERS.IE &&\n $.Browser.version < 9\n ) || (\n $.Browser.vendor == $.BROWSERS.CHROME &&\n $.Browser.version < 2\n )\n );\n\n //determine if this browser supports element.style.opacity\n $.Browser.opacity = !(\n $.Browser.vendor == $.BROWSERS.IE &&\n $.Browser.version < 9\n );\n\n })();\n\n\n //TODO: $.console is often used inside a try/catch block which generally\n // prevents allowings errors to occur with detection until a debugger\n // is attached. Although I've been guilty of the same anti-pattern\n // I eventually was convinced that errors should naturally propogate in\n // all but the most special cases.\n /**\n * A convenient alias for console when available, and a simple null\n * function when console is unavailable.\n * @static\n * @private\n */\n var nullfunction = function( msg ){\n //document.location.hash = msg;\n };\n\n $.console = window.console || {\n log: nullfunction,\n debug: nullfunction,\n info: nullfunction,\n warn: nullfunction,\n error: nullfunction,\n assert: nullfunction\n };\n\n\n // Adding support for HTML5's requestAnimationFrame as suggested by acdha.\n // Implementation taken from matt synder's post here:\n // http://mattsnider.com/cross-browser-and-legacy-supported-requestframeanimation/\n (function( w ) {\n\n // most browsers have an implementation\n var requestAnimationFrame = w.requestAnimationFrame ||\n w.mozRequestAnimationFrame ||\n w.webkitRequestAnimationFrame ||\n w.msRequestAnimationFrame;\n\n var cancelAnimationFrame = w.cancelAnimationFrame ||\n w.mozCancelAnimationFrame ||\n w.webkitCancelAnimationFrame ||\n w.msCancelAnimationFrame;\n\n // polyfill, when necessary\n if ( requestAnimationFrame && cancelAnimationFrame ) {\n // We can't assign these window methods directly to $ because they\n // expect their \"this\" to be \"window\", so we call them in wrappers.\n $.requestAnimationFrame = function(){\n return requestAnimationFrame.apply( w, arguments );\n };\n $.cancelAnimationFrame = function(){\n return cancelAnimationFrame.apply( w, arguments );\n };\n } else {\n var aAnimQueue = [],\n processing = [],\n iRequestId = 0,\n iIntervalId;\n\n // create a mock requestAnimationFrame function\n $.requestAnimationFrame = function( callback ) {\n aAnimQueue.push( [ ++iRequestId, callback ] );\n\n if ( !iIntervalId ) {\n iIntervalId = setInterval( function() {\n if ( aAnimQueue.length ) {\n var time = $.now();\n // Process all of the currently outstanding frame\n // requests, but none that get added during the\n // processing.\n // Swap the arrays so we don't have to create a new\n // array every frame.\n var temp = processing;\n processing = aAnimQueue;\n aAnimQueue = temp;\n while ( processing.length ) {\n processing.shift()[ 1 ]( time );\n }\n } else {\n // don't continue the interval, if unnecessary\n clearInterval( iIntervalId );\n iIntervalId = undefined;\n }\n }, 1000 / 50); // estimating support for 50 frames per second\n }\n\n return iRequestId;\n };\n\n // create a mock cancelAnimationFrame function\n $.cancelAnimationFrame = function( requestId ) {\n // find the request ID and remove it\n var i, j;\n for ( i = 0, j = aAnimQueue.length; i < j; i += 1 ) {\n if ( aAnimQueue[ i ][ 0 ] === requestId ) {\n aAnimQueue.splice( i, 1 );\n return;\n }\n }\n\n // If it's not in the queue, it may be in the set we're currently\n // processing (if cancelAnimationFrame is called from within a\n // requestAnimationFrame callback).\n for ( i = 0, j = processing.length; i < j; i += 1 ) {\n if ( processing[ i ][ 0 ] === requestId ) {\n processing.splice( i, 1 );\n return;\n }\n }\n };\n }\n })( window );\n\n /**\n * @private\n * @inner\n * @function\n * @param {Element} element\n * @param {Boolean} [isFixed]\n * @returns {Element}\n */\n function getOffsetParent( element, isFixed ) {\n if ( isFixed && element != document.body ) {\n return document.body;\n } else {\n return element.offsetParent;\n }\n }\n\n}(OpenSeadragon));\n\n\n// Universal Module Definition, supports CommonJS, AMD and simple script tag\n(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // expose as amd module\n define([], factory);\n } else if (typeof module === 'object' && module.exports) {\n // expose as commonjs module\n module.exports = factory();\n } else {\n // expose as window.OpenSeadragon\n root.OpenSeadragon = factory();\n }\n}(this, function () {\n return OpenSeadragon;\n}));\n","/*\n * OpenSeadragon - full-screen support functions\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ) {\n /**\n * Determine native full screen support we can get from the browser.\n * @member fullScreenApi\n * @memberof OpenSeadragon\n * @type {object}\n * @property {Boolean} supportsFullScreen Return true if full screen API is supported.\n * @property {Function} isFullScreen Return true if currently in full screen mode.\n * @property {Function} getFullScreenElement Return the element currently in full screen mode.\n * @property {Function} requestFullScreen Make a request to go in full screen mode.\n * @property {Function} exitFullScreen Make a request to exit full screen mode.\n * @property {Function} cancelFullScreen Deprecated, use exitFullScreen instead.\n * @property {String} fullScreenEventName Event fired when the full screen mode change.\n * @property {String} fullScreenErrorEventName Event fired when a request to go\n * in full screen mode failed.\n */\n var fullScreenApi = {\n supportsFullScreen: false,\n isFullScreen: function() { return false; },\n getFullScreenElement: function() { return null; },\n requestFullScreen: function() {},\n exitFullScreen: function() {},\n cancelFullScreen: function() {},\n fullScreenEventName: '',\n fullScreenErrorEventName: ''\n };\n\n // check for native support\n if ( document.exitFullscreen ) {\n // W3C standard\n fullScreenApi.supportsFullScreen = true;\n fullScreenApi.getFullScreenElement = function() {\n return document.fullscreenElement;\n };\n fullScreenApi.requestFullScreen = function( element ) {\n return element.requestFullscreen();\n };\n fullScreenApi.exitFullScreen = function() {\n document.exitFullscreen();\n };\n fullScreenApi.fullScreenEventName = \"fullscreenchange\";\n fullScreenApi.fullScreenErrorEventName = \"fullscreenerror\";\n } else if ( document.msExitFullscreen ) {\n // IE 11\n fullScreenApi.supportsFullScreen = true;\n fullScreenApi.getFullScreenElement = function() {\n return document.msFullscreenElement;\n };\n fullScreenApi.requestFullScreen = function( element ) {\n return element.msRequestFullscreen();\n };\n fullScreenApi.exitFullScreen = function() {\n document.msExitFullscreen();\n };\n fullScreenApi.fullScreenEventName = \"MSFullscreenChange\";\n fullScreenApi.fullScreenErrorEventName = \"MSFullscreenError\";\n } else if ( document.webkitExitFullscreen ) {\n // Recent webkit\n fullScreenApi.supportsFullScreen = true;\n fullScreenApi.getFullScreenElement = function() {\n return document.webkitFullscreenElement;\n };\n fullScreenApi.requestFullScreen = function( element ) {\n return element.webkitRequestFullscreen();\n };\n fullScreenApi.exitFullScreen = function() {\n document.webkitExitFullscreen();\n };\n fullScreenApi.fullScreenEventName = \"webkitfullscreenchange\";\n fullScreenApi.fullScreenErrorEventName = \"webkitfullscreenerror\";\n } else if ( document.webkitCancelFullScreen ) {\n // Old webkit\n fullScreenApi.supportsFullScreen = true;\n fullScreenApi.getFullScreenElement = function() {\n return document.webkitCurrentFullScreenElement;\n };\n fullScreenApi.requestFullScreen = function( element ) {\n return element.webkitRequestFullScreen();\n };\n fullScreenApi.exitFullScreen = function() {\n document.webkitCancelFullScreen();\n };\n fullScreenApi.fullScreenEventName = \"webkitfullscreenchange\";\n fullScreenApi.fullScreenErrorEventName = \"webkitfullscreenerror\";\n } else if ( document.mozCancelFullScreen ) {\n // Firefox\n fullScreenApi.supportsFullScreen = true;\n fullScreenApi.getFullScreenElement = function() {\n return document.mozFullScreenElement;\n };\n fullScreenApi.requestFullScreen = function( element ) {\n return element.mozRequestFullScreen();\n };\n fullScreenApi.exitFullScreen = function() {\n document.mozCancelFullScreen();\n };\n fullScreenApi.fullScreenEventName = \"mozfullscreenchange\";\n fullScreenApi.fullScreenErrorEventName = \"mozfullscreenerror\";\n }\n fullScreenApi.isFullScreen = function() {\n return fullScreenApi.getFullScreenElement() !== null;\n };\n fullScreenApi.cancelFullScreen = function() {\n $.console.error(\"cancelFullScreen is deprecated. Use exitFullScreen instead.\");\n fullScreenApi.exitFullScreen();\n };\n\n // export api\n $.extend( $, fullScreenApi );\n\n})( OpenSeadragon );\n","/*\n * OpenSeadragon - EventSource\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function($){\n\n/**\n * Event handler method signature used by all OpenSeadragon events.\n *\n * @callback EventHandler\n * @memberof OpenSeadragon\n * @param {Object} event - See individual events for event-specific properties.\n */\n\n\n/**\n * @class EventSource\n * @classdesc For use by classes which want to support custom, non-browser events.\n *\n * @memberof OpenSeadragon\n */\n$.EventSource = function() {\n this.events = {};\n};\n\n/** @lends OpenSeadragon.EventSource.prototype */\n$.EventSource.prototype = {\n\n /**\n * Add an event handler to be triggered only once (or a given number of times)\n * for a given event.\n * @function\n * @param {String} eventName - Name of event to register.\n * @param {OpenSeadragon.EventHandler} handler - Function to call when event\n * is triggered.\n * @param {Object} [userData=null] - Arbitrary object to be passed unchanged\n * to the handler.\n * @param {Number} [times=1] - The number of times to handle the event\n * before removing it.\n */\n addOnceHandler: function(eventName, handler, userData, times) {\n var self = this;\n times = times || 1;\n var count = 0;\n var onceHandler = function(event) {\n count++;\n if (count === times) {\n self.removeHandler(eventName, onceHandler);\n }\n handler(event);\n };\n this.addHandler(eventName, onceHandler, userData);\n },\n\n /**\n * Add an event handler for a given event.\n * @function\n * @param {String} eventName - Name of event to register.\n * @param {OpenSeadragon.EventHandler} handler - Function to call when event is triggered.\n * @param {Object} [userData=null] - Arbitrary object to be passed unchanged to the handler.\n */\n addHandler: function ( eventName, handler, userData ) {\n var events = this.events[ eventName ];\n if ( !events ) {\n this.events[ eventName ] = events = [];\n }\n if ( handler && $.isFunction( handler ) ) {\n events[ events.length ] = { handler: handler, userData: userData || null };\n }\n },\n\n /**\n * Remove a specific event handler for a given event.\n * @function\n * @param {String} eventName - Name of event for which the handler is to be removed.\n * @param {OpenSeadragon.EventHandler} handler - Function to be removed.\n */\n removeHandler: function ( eventName, handler ) {\n var events = this.events[ eventName ],\n handlers = [],\n i;\n if ( !events ) {\n return;\n }\n if ( $.isArray( events ) ) {\n for ( i = 0; i < events.length; i++ ) {\n if ( events[i].handler !== handler ) {\n handlers.push( events[ i ] );\n }\n }\n this.events[ eventName ] = handlers;\n }\n },\n\n\n /**\n * Remove all event handlers for a given event type. If no type is given all\n * event handlers for every event type are removed.\n * @function\n * @param {String} eventName - Name of event for which all handlers are to be removed.\n */\n removeAllHandlers: function( eventName ) {\n if ( eventName ){\n this.events[ eventName ] = [];\n } else{\n for ( var eventType in this.events ) {\n this.events[ eventType ] = [];\n }\n }\n },\n\n /**\n * Get a function which iterates the list of all handlers registered for a given event, calling the handler for each.\n * @function\n * @param {String} eventName - Name of event to get handlers for.\n */\n getHandler: function ( eventName ) {\n var events = this.events[ eventName ];\n if ( !events || !events.length ) {\n return null;\n }\n events = events.length === 1 ?\n [ events[ 0 ] ] :\n Array.apply( null, events );\n return function ( source, args ) {\n var i,\n length = events.length;\n for ( i = 0; i < length; i++ ) {\n if ( events[ i ] ) {\n args.eventSource = source;\n args.userData = events[ i ].userData;\n events[ i ].handler( args );\n }\n }\n };\n },\n\n /**\n * Trigger an event, optionally passing additional information.\n * @function\n * @param {String} eventName - Name of event to register.\n * @param {Object} eventArgs - Event-specific data.\n */\n raiseEvent: function( eventName, eventArgs ) {\n //uncomment if you want to get a log of all events\n //$.console.log( eventName );\n var handler = this.getHandler( eventName );\n\n if ( handler ) {\n if ( !eventArgs ) {\n eventArgs = {};\n }\n\n handler( this, eventArgs );\n }\n }\n};\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - MouseTracker\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function ( $ ) {\n\n // All MouseTracker instances\n var MOUSETRACKERS = [];\n\n // dictionary from hash to private properties\n var THIS = {};\n\n\n /**\n * @class MouseTracker\n * @classdesc Provides simplified handling of common pointer device (mouse, touch, pen, etc.) gestures\n * and keyboard events on a specified element.\n * @memberof OpenSeadragon\n * @param {Object} options\n * Allows configurable properties to be entirely specified by passing\n * an options object to the constructor. The constructor also supports\n * the original positional arguments 'element', 'clickTimeThreshold',\n * and 'clickDistThreshold' in that order.\n * @param {Element|String} options.element\n * A reference to an element or an element id for which the pointer/key\n * events will be monitored.\n * @param {Boolean} [options.startDisabled=false]\n * If true, event tracking on the element will not start until\n * {@link OpenSeadragon.MouseTracker.setTracking|setTracking} is called.\n * @param {Number} options.clickTimeThreshold\n * The number of milliseconds within which a pointer down-up event combination\n * will be treated as a click gesture.\n * @param {Number} options.clickDistThreshold\n * The maximum distance allowed between a pointer down event and a pointer up event\n * to be treated as a click gesture.\n * @param {Number} options.dblClickTimeThreshold\n * The number of milliseconds within which two pointer down-up event combinations\n * will be treated as a double-click gesture.\n * @param {Number} options.dblClickDistThreshold\n * The maximum distance allowed between two pointer click events\n * to be treated as a click gesture.\n * @param {Number} [options.stopDelay=50]\n * The number of milliseconds without pointer move before the stop\n * event is fired.\n * @param {OpenSeadragon.EventHandler} [options.enterHandler=null]\n * An optional handler for pointer enter.\n * @param {OpenSeadragon.EventHandler} [options.exitHandler=null]\n * An optional handler for pointer exit.\n * @param {OpenSeadragon.EventHandler} [options.pressHandler=null]\n * An optional handler for pointer press.\n * @param {OpenSeadragon.EventHandler} [options.nonPrimaryPressHandler=null]\n * An optional handler for pointer non-primary button press.\n * @param {OpenSeadragon.EventHandler} [options.releaseHandler=null]\n * An optional handler for pointer release.\n * @param {OpenSeadragon.EventHandler} [options.nonPrimaryReleaseHandler=null]\n * An optional handler for pointer non-primary button release.\n * @param {OpenSeadragon.EventHandler} [options.moveHandler=null]\n * An optional handler for pointer move.\n * @param {OpenSeadragon.EventHandler} [options.scrollHandler=null]\n * An optional handler for mouse wheel scroll.\n * @param {OpenSeadragon.EventHandler} [options.clickHandler=null]\n * An optional handler for pointer click.\n * @param {OpenSeadragon.EventHandler} [options.dblClickHandler=null]\n * An optional handler for pointer double-click.\n * @param {OpenSeadragon.EventHandler} [options.dragHandler=null]\n * An optional handler for the drag gesture.\n * @param {OpenSeadragon.EventHandler} [options.dragEndHandler=null]\n * An optional handler for after a drag gesture.\n * @param {OpenSeadragon.EventHandler} [options.pinchHandler=null]\n * An optional handler for the pinch gesture.\n * @param {OpenSeadragon.EventHandler} [options.keyDownHandler=null]\n * An optional handler for keydown.\n * @param {OpenSeadragon.EventHandler} [options.keyUpHandler=null]\n * An optional handler for keyup.\n * @param {OpenSeadragon.EventHandler} [options.keyHandler=null]\n * An optional handler for keypress.\n * @param {OpenSeadragon.EventHandler} [options.focusHandler=null]\n * An optional handler for focus.\n * @param {OpenSeadragon.EventHandler} [options.blurHandler=null]\n * An optional handler for blur.\n * @param {Object} [options.userData=null]\n * Arbitrary object to be passed unchanged to any attached handler methods.\n */\n $.MouseTracker = function ( options ) {\n\n MOUSETRACKERS.push( this );\n\n var args = arguments;\n\n if ( !$.isPlainObject( options ) ) {\n options = {\n element: args[ 0 ],\n clickTimeThreshold: args[ 1 ],\n clickDistThreshold: args[ 2 ]\n };\n }\n\n this.hash = Math.random(); // An unique hash for this tracker.\n /**\n * The element for which pointer events are being monitored.\n * @member {Element} element\n * @memberof OpenSeadragon.MouseTracker#\n */\n this.element = $.getElement( options.element );\n /**\n * The number of milliseconds within which a pointer down-up event combination\n * will be treated as a click gesture.\n * @member {Number} clickTimeThreshold\n * @memberof OpenSeadragon.MouseTracker#\n */\n this.clickTimeThreshold = options.clickTimeThreshold || $.DEFAULT_SETTINGS.clickTimeThreshold;\n /**\n * The maximum distance allowed between a pointer down event and a pointer up event\n * to be treated as a click gesture.\n * @member {Number} clickDistThreshold\n * @memberof OpenSeadragon.MouseTracker#\n */\n this.clickDistThreshold = options.clickDistThreshold || $.DEFAULT_SETTINGS.clickDistThreshold;\n /**\n * The number of milliseconds within which two pointer down-up event combinations\n * will be treated as a double-click gesture.\n * @member {Number} dblClickTimeThreshold\n * @memberof OpenSeadragon.MouseTracker#\n */\n this.dblClickTimeThreshold = options.dblClickTimeThreshold || $.DEFAULT_SETTINGS.dblClickTimeThreshold;\n /**\n * The maximum distance allowed between two pointer click events\n * to be treated as a click gesture.\n * @member {Number} clickDistThreshold\n * @memberof OpenSeadragon.MouseTracker#\n */\n this.dblClickDistThreshold = options.dblClickDistThreshold || $.DEFAULT_SETTINGS.dblClickDistThreshold;\n /*eslint-disable no-multi-spaces*/\n this.userData = options.userData || null;\n this.stopDelay = options.stopDelay || 50;\n\n this.enterHandler = options.enterHandler || null;\n this.exitHandler = options.exitHandler || null;\n this.pressHandler = options.pressHandler || null;\n this.nonPrimaryPressHandler = options.nonPrimaryPressHandler || null;\n this.releaseHandler = options.releaseHandler || null;\n this.nonPrimaryReleaseHandler = options.nonPrimaryReleaseHandler || null;\n this.moveHandler = options.moveHandler || null;\n this.scrollHandler = options.scrollHandler || null;\n this.clickHandler = options.clickHandler || null;\n this.dblClickHandler = options.dblClickHandler || null;\n this.dragHandler = options.dragHandler || null;\n this.dragEndHandler = options.dragEndHandler || null;\n this.pinchHandler = options.pinchHandler || null;\n this.stopHandler = options.stopHandler || null;\n this.keyDownHandler = options.keyDownHandler || null;\n this.keyUpHandler = options.keyUpHandler || null;\n this.keyHandler = options.keyHandler || null;\n this.focusHandler = options.focusHandler || null;\n this.blurHandler = options.blurHandler || null;\n /*eslint-enable no-multi-spaces*/\n\n //Store private properties in a scope sealed hash map\n var _this = this;\n\n /**\n * @private\n * @property {Boolean} tracking\n * Are we currently tracking pointer events for this element.\n */\n THIS[ this.hash ] = {\n click: function ( event ) { onClick( _this, event ); },\n dblclick: function ( event ) { onDblClick( _this, event ); },\n keydown: function ( event ) { onKeyDown( _this, event ); },\n keyup: function ( event ) { onKeyUp( _this, event ); },\n keypress: function ( event ) { onKeyPress( _this, event ); },\n focus: function ( event ) { onFocus( _this, event ); },\n blur: function ( event ) { onBlur( _this, event ); },\n\n wheel: function ( event ) { onWheel( _this, event ); },\n mousewheel: function ( event ) { onMouseWheel( _this, event ); },\n DOMMouseScroll: function ( event ) { onMouseWheel( _this, event ); },\n MozMousePixelScroll: function ( event ) { onMouseWheel( _this, event ); },\n\n mouseenter: function ( event ) { onMouseEnter( _this, event ); }, // Used on IE8 only\n mouseleave: function ( event ) { onMouseLeave( _this, event ); }, // Used on IE8 only\n mouseover: function ( event ) { onMouseOver( _this, event ); },\n mouseout: function ( event ) { onMouseOut( _this, event ); },\n mousedown: function ( event ) { onMouseDown( _this, event ); },\n mouseup: function ( event ) { onMouseUp( _this, event ); },\n mouseupcaptured: function ( event ) { onMouseUpCaptured( _this, event ); },\n mousemove: function ( event ) { onMouseMove( _this, event ); },\n mousemovecaptured: function ( event ) { onMouseMoveCaptured( _this, event ); },\n\n touchstart: function ( event ) { onTouchStart( _this, event ); },\n touchend: function ( event ) { onTouchEnd( _this, event ); },\n touchendcaptured: function ( event ) { onTouchEndCaptured( _this, event ); },\n touchmove: function ( event ) { onTouchMove( _this, event ); },\n touchmovecaptured: function ( event ) { onTouchMoveCaptured( _this, event ); },\n touchcancel: function ( event ) { onTouchCancel( _this, event ); },\n\n gesturestart: function ( event ) { onGestureStart( _this, event ); },\n gesturechange: function ( event ) { onGestureChange( _this, event ); },\n\n pointerover: function ( event ) { onPointerOver( _this, event ); },\n MSPointerOver: function ( event ) { onPointerOver( _this, event ); },\n pointerout: function ( event ) { onPointerOut( _this, event ); },\n MSPointerOut: function ( event ) { onPointerOut( _this, event ); },\n pointerdown: function ( event ) { onPointerDown( _this, event ); },\n MSPointerDown: function ( event ) { onPointerDown( _this, event ); },\n pointerup: function ( event ) { onPointerUp( _this, event ); },\n MSPointerUp: function ( event ) { onPointerUp( _this, event ); },\n pointermove: function ( event ) { onPointerMove( _this, event ); },\n MSPointerMove: function ( event ) { onPointerMove( _this, event ); },\n pointercancel: function ( event ) { onPointerCancel( _this, event ); },\n MSPointerCancel: function ( event ) { onPointerCancel( _this, event ); },\n pointerupcaptured: function ( event ) { onPointerUpCaptured( _this, event ); },\n pointermovecaptured: function ( event ) { onPointerMoveCaptured( _this, event ); },\n\n tracking: false,\n\n // Active pointers lists. Array of GesturePointList objects, one for each pointer device type.\n // GesturePointList objects are added each time a pointer is tracked by a new pointer device type (see getActivePointersListByType()).\n // Active pointers are any pointer being tracked for this element which are in the hit-test area\n // of the element (for hover-capable devices) and/or have contact or a button press initiated in the element.\n activePointersLists: [],\n\n // Tracking for double-click gesture\n lastClickPos: null,\n dblClickTimeOut: null,\n\n // Tracking for pinch gesture\n pinchGPoints: [],\n lastPinchDist: 0,\n currentPinchDist: 0,\n lastPinchCenter: null,\n currentPinchCenter: null\n };\n\n if ( !options.startDisabled ) {\n this.setTracking( true );\n }\n };\n\n /** @lends OpenSeadragon.MouseTracker.prototype */\n $.MouseTracker.prototype = {\n\n /**\n * Clean up any events or objects created by the tracker.\n * @function\n */\n destroy: function () {\n var i;\n\n stopTracking( this );\n this.element = null;\n\n for ( i = 0; i < MOUSETRACKERS.length; i++ ) {\n if ( MOUSETRACKERS[ i ] === this ) {\n MOUSETRACKERS.splice( i, 1 );\n break;\n }\n }\n\n THIS[ this.hash ] = null;\n delete THIS[ this.hash ];\n },\n\n /**\n * Are we currently tracking events on this element.\n * @deprecated Just use this.tracking\n * @function\n * @returns {Boolean} Are we currently tracking events on this element.\n */\n isTracking: function () {\n return THIS[ this.hash ].tracking;\n },\n\n /**\n * Enable or disable whether or not we are tracking events on this element.\n * @function\n * @param {Boolean} track True to start tracking, false to stop tracking.\n * @returns {OpenSeadragon.MouseTracker} Chainable.\n */\n setTracking: function ( track ) {\n if ( track ) {\n startTracking( this );\n } else {\n stopTracking( this );\n }\n //chain\n return this;\n },\n\n /**\n * Returns the {@link OpenSeadragon.MouseTracker.GesturePointList|GesturePointList} for all but the given pointer device type.\n * @function\n * @param {String} type - The pointer device type: \"mouse\", \"touch\", \"pen\", etc.\n * @returns {Array.}\n */\n getActivePointersListsExceptType: function ( type ) {\n var delegate = THIS[ this.hash ];\n var listArray = [];\n\n for (var i = 0; i < delegate.activePointersLists.length; ++i) {\n if (delegate.activePointersLists[i].type !== type) {\n listArray.push(delegate.activePointersLists[i]);\n }\n }\n\n return listArray;\n },\n\n /**\n * Returns the {@link OpenSeadragon.MouseTracker.GesturePointList|GesturePointList} for the given pointer device type,\n * creating and caching a new {@link OpenSeadragon.MouseTracker.GesturePointList|GesturePointList} if one doesn't already exist for the type.\n * @function\n * @param {String} type - The pointer device type: \"mouse\", \"touch\", \"pen\", etc.\n * @returns {OpenSeadragon.MouseTracker.GesturePointList}\n */\n getActivePointersListByType: function ( type ) {\n var delegate = THIS[ this.hash ],\n i,\n len = delegate.activePointersLists.length,\n list;\n\n for ( i = 0; i < len; i++ ) {\n if ( delegate.activePointersLists[ i ].type === type ) {\n return delegate.activePointersLists[ i ];\n }\n }\n\n list = new $.MouseTracker.GesturePointList( type );\n delegate.activePointersLists.push( list );\n return list;\n },\n\n /**\n * Returns the total number of pointers currently active on the tracked element.\n * @function\n * @returns {Number}\n */\n getActivePointerCount: function () {\n var delegate = THIS[ this.hash ],\n i,\n len = delegate.activePointersLists.length,\n count = 0;\n\n for ( i = 0; i < len; i++ ) {\n count += delegate.activePointersLists[ i ].getLength();\n }\n\n return count;\n },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {Number} event.pointers\n * Number of pointers (all types) active in the tracked element.\n * @param {Boolean} event.insideElementPressed\n * True if the left mouse button is currently being pressed and was\n * initiated inside the tracked element, otherwise false.\n * @param {Boolean} event.buttonDownAny\n * Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n enterHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {Number} event.pointers\n * Number of pointers (all types) active in the tracked element.\n * @param {Boolean} event.insideElementPressed\n * True if the left mouse button is currently being pressed and was\n * initiated inside the tracked element, otherwise false.\n * @param {Boolean} event.buttonDownAny\n * Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n exitHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n pressHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.button\n * Button which caused the event.\n * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n nonPrimaryPressHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {Boolean} event.insideElementPressed\n * True if the left mouse button is currently being pressed and was\n * initiated inside the tracked element, otherwise false.\n * @param {Boolean} event.insideElementReleased\n * True if the cursor inside the tracked element when the button was released.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n releaseHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.button\n * Button which caused the event.\n * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n nonPrimaryReleaseHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n moveHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.scroll\n * The scroll delta for the event.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. Touch devices no longer generate scroll event.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n scrollHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Boolean} event.quick\n * True only if the clickDistThreshold and clickTimeThreshold are both passed. Useful for ignoring drag events.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n clickHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n dblClickHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {OpenSeadragon.Point} event.delta\n * The x,y components of the difference between the current position and the last drag event position. Useful for ignoring or weighting the events.\n * @param {Number} event.speed\n * Current computed speed, in pixels per second.\n * @param {Number} event.direction\n * Current computed direction, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n dragHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.speed\n * Speed at the end of a drag gesture, in pixels per second.\n * @param {Number} event.direction\n * Direction at the end of a drag gesture, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n dragEndHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {Array.} event.gesturePoints\n * Gesture points associated with the gesture. Velocity data can be found here.\n * @param {OpenSeadragon.Point} event.lastCenter\n * The previous center point of the two pinch contact points relative to the tracked element.\n * @param {OpenSeadragon.Point} event.center\n * The center point of the two pinch contact points relative to the tracked element.\n * @param {Number} event.lastDistance\n * The previous distance between the two pinch contact points in CSS pixels.\n * @param {Number} event.distance\n * The distance between the two pinch contact points in CSS pixels.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n pinchHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n stopHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {Number} event.keyCode\n * The key code that was pressed.\n * @param {Boolean} event.ctrl\n * True if the ctrl key was pressed during this event.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Boolean} event.alt\n * True if the alt key was pressed during this event.\n * @param {Boolean} event.meta\n * True if the meta key was pressed during this event.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n keyDownHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {Number} event.keyCode\n * The key code that was pressed.\n * @param {Boolean} event.ctrl\n * True if the ctrl key was pressed during this event.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Boolean} event.alt\n * True if the alt key was pressed during this event.\n * @param {Boolean} event.meta\n * True if the meta key was pressed during this event.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n keyUpHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {Number} event.keyCode\n * The key code that was pressed.\n * @param {Boolean} event.ctrl\n * True if the ctrl key was pressed during this event.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Boolean} event.alt\n * True if the alt key was pressed during this event.\n * @param {Boolean} event.meta\n * True if the meta key was pressed during this event.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n keyHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n focusHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n blurHandler: function () { }\n };\n\n /**\n * Resets all active mousetrakers. (Added to patch issue #697 \"Mouse up outside map will cause \"canvas-drag\" event to stick\")\n *\n * @private\n * @member resetAllMouseTrackers\n * @memberof OpenSeadragon.MouseTracker\n */\n $.MouseTracker.resetAllMouseTrackers = function(){\n for(var i = 0; i < MOUSETRACKERS.length; i++){\n if (MOUSETRACKERS[i].isTracking()){\n MOUSETRACKERS[i].setTracking(false);\n MOUSETRACKERS[i].setTracking(true);\n }\n }\n };\n\n /**\n * Provides continuous computation of velocity (speed and direction) of active pointers.\n * This is a singleton, used by all MouseTracker instances, as it is unlikely there will ever be more than\n * two active gesture pointers at a time.\n *\n * @private\n * @member gesturePointVelocityTracker\n * @memberof OpenSeadragon.MouseTracker\n */\n $.MouseTracker.gesturePointVelocityTracker = (function () {\n var trackerPoints = [],\n intervalId = 0,\n lastTime = 0;\n\n // Generates a unique identifier for a tracked gesture point\n var _generateGuid = function ( tracker, gPoint ) {\n return tracker.hash.toString() + gPoint.type + gPoint.id.toString();\n };\n\n // Interval timer callback. Computes velocity for all tracked gesture points.\n var _doTracking = function () {\n var i,\n len = trackerPoints.length,\n trackPoint,\n gPoint,\n now = $.now(),\n elapsedTime,\n distance,\n speed;\n\n elapsedTime = now - lastTime;\n lastTime = now;\n\n for ( i = 0; i < len; i++ ) {\n trackPoint = trackerPoints[ i ];\n gPoint = trackPoint.gPoint;\n // Math.atan2 gives us just what we need for a velocity vector, as we can simply\n // use cos()/sin() to extract the x/y velocity components.\n gPoint.direction = Math.atan2( gPoint.currentPos.y - trackPoint.lastPos.y, gPoint.currentPos.x - trackPoint.lastPos.x );\n // speed = distance / elapsed time\n distance = trackPoint.lastPos.distanceTo( gPoint.currentPos );\n trackPoint.lastPos = gPoint.currentPos;\n speed = 1000 * distance / ( elapsedTime + 1 );\n // Simple biased average, favors the most recent speed computation. Smooths out erratic gestures a bit.\n gPoint.speed = 0.75 * speed + 0.25 * gPoint.speed;\n }\n };\n\n // Public. Add a gesture point to be tracked\n var addPoint = function ( tracker, gPoint ) {\n var guid = _generateGuid( tracker, gPoint );\n\n trackerPoints.push(\n {\n guid: guid,\n gPoint: gPoint,\n lastPos: gPoint.currentPos\n } );\n\n // Only fire up the interval timer when there's gesture pointers to track\n if ( trackerPoints.length === 1 ) {\n lastTime = $.now();\n intervalId = window.setInterval( _doTracking, 50 );\n }\n };\n\n // Public. Stop tracking a gesture point\n var removePoint = function ( tracker, gPoint ) {\n var guid = _generateGuid( tracker, gPoint ),\n i,\n len = trackerPoints.length;\n for ( i = 0; i < len; i++ ) {\n if ( trackerPoints[ i ].guid === guid ) {\n trackerPoints.splice( i, 1 );\n // Only run the interval timer if theres gesture pointers to track\n len--;\n if ( len === 0 ) {\n window.clearInterval( intervalId );\n }\n break;\n }\n }\n };\n\n return {\n addPoint: addPoint,\n removePoint: removePoint\n };\n } )();\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Pointer event model and feature detection\n///////////////////////////////////////////////////////////////////////////////\n\n $.MouseTracker.captureElement = document;\n\n /**\n * Detect available mouse wheel event name.\n */\n $.MouseTracker.wheelEventName = ( $.Browser.vendor == $.BROWSERS.IE && $.Browser.version > 8 ) ||\n ( 'onwheel' in document.createElement( 'div' ) ) ? 'wheel' : // Modern browsers support 'wheel'\n document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least 'mousewheel'\n 'DOMMouseScroll'; // Assume old Firefox\n\n /**\n * Detect legacy mouse capture support.\n */\n $.MouseTracker.supportsMouseCapture = (function () {\n var divElement = document.createElement( 'div' );\n return $.isFunction( divElement.setCapture ) && $.isFunction( divElement.releaseCapture );\n }());\n\n /**\n * Detect browser pointer device event model(s) and build appropriate list of events to subscribe to.\n */\n $.MouseTracker.subscribeEvents = [ \"click\", \"dblclick\", \"keydown\", \"keyup\", \"keypress\", \"focus\", \"blur\", $.MouseTracker.wheelEventName ];\n\n if( $.MouseTracker.wheelEventName == \"DOMMouseScroll\" ) {\n // Older Firefox\n $.MouseTracker.subscribeEvents.push( \"MozMousePixelScroll\" );\n }\n\n // Note: window.navigator.pointerEnable is deprecated on IE 11 and not part of W3C spec.\n if ( window.PointerEvent && ( window.navigator.pointerEnabled || $.Browser.vendor !== $.BROWSERS.IE ) ) {\n // IE11 and other W3C Pointer Event implementations (see http://www.w3.org/TR/pointerevents)\n $.MouseTracker.havePointerEvents = true;\n $.MouseTracker.subscribeEvents.push( \"pointerover\", \"pointerout\", \"pointerdown\", \"pointerup\", \"pointermove\", \"pointercancel\" );\n $.MouseTracker.unprefixedPointerEvents = true;\n if( navigator.maxTouchPoints ) {\n $.MouseTracker.maxTouchPoints = navigator.maxTouchPoints;\n } else {\n $.MouseTracker.maxTouchPoints = 0;\n }\n $.MouseTracker.haveMouseEnter = false;\n } else if ( window.MSPointerEvent && window.navigator.msPointerEnabled ) {\n // IE10\n $.MouseTracker.havePointerEvents = true;\n $.MouseTracker.subscribeEvents.push( \"MSPointerOver\", \"MSPointerOut\", \"MSPointerDown\", \"MSPointerUp\", \"MSPointerMove\", \"MSPointerCancel\" );\n $.MouseTracker.unprefixedPointerEvents = false;\n if( navigator.msMaxTouchPoints ) {\n $.MouseTracker.maxTouchPoints = navigator.msMaxTouchPoints;\n } else {\n $.MouseTracker.maxTouchPoints = 0;\n }\n $.MouseTracker.haveMouseEnter = false;\n } else {\n // Legacy W3C mouse events\n $.MouseTracker.havePointerEvents = false;\n if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {\n $.MouseTracker.subscribeEvents.push( \"mouseenter\", \"mouseleave\" );\n $.MouseTracker.haveMouseEnter = true;\n } else {\n $.MouseTracker.subscribeEvents.push( \"mouseover\", \"mouseout\" );\n $.MouseTracker.haveMouseEnter = false;\n }\n $.MouseTracker.subscribeEvents.push( \"mousedown\", \"mouseup\", \"mousemove\" );\n if ( 'ontouchstart' in window ) {\n // iOS, Android, and other W3c Touch Event implementations\n // (see http://www.w3.org/TR/touch-events/)\n // (see https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html)\n // (see https://developer.apple.com/library/safari/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html)\n $.MouseTracker.subscribeEvents.push( \"touchstart\", \"touchend\", \"touchmove\", \"touchcancel\" );\n }\n if ( 'ongesturestart' in window ) {\n // iOS (see https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html)\n // Subscribe to these to prevent default gesture handling\n $.MouseTracker.subscribeEvents.push( \"gesturestart\", \"gesturechange\" );\n }\n $.MouseTracker.mousePointerId = \"legacy-mouse\";\n $.MouseTracker.maxTouchPoints = 10;\n }\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes and typedefs\n///////////////////////////////////////////////////////////////////////////////\n\n /**\n * Represents a point of contact on the screen made by a mouse cursor, pen, touch, or other pointer device.\n *\n * @typedef {Object} GesturePoint\n * @memberof OpenSeadragon.MouseTracker\n *\n * @property {Number} id\n * Identifier unique from all other active GesturePoints for a given pointer device.\n * @property {String} type\n * The pointer device type: \"mouse\", \"touch\", \"pen\", etc.\n * @property {Boolean} captured\n * True if events for the gesture point are captured to the tracked element.\n * @property {Boolean} isPrimary\n * True if the gesture point is a master pointer amongst the set of active pointers for each pointer type. True for mouse and primary (first) touch/pen pointers.\n * @property {Boolean} insideElementPressed\n * True if button pressed or contact point initiated inside the screen area of the tracked element.\n * @property {Boolean} insideElement\n * True if pointer or contact point is currently inside the bounds of the tracked element.\n * @property {Number} speed\n * Current computed speed, in pixels per second.\n * @property {Number} direction\n * Current computed direction, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0.\n * @property {OpenSeadragon.Point} contactPos\n * The initial pointer contact position, relative to the page including any scrolling. Only valid if the pointer has contact (pressed, touch contact, pen contact).\n * @property {Number} contactTime\n * The initial pointer contact time, in milliseconds. Only valid if the pointer has contact (pressed, touch contact, pen contact).\n * @property {OpenSeadragon.Point} lastPos\n * The last pointer position, relative to the page including any scrolling.\n * @property {Number} lastTime\n * The last pointer contact time, in milliseconds.\n * @property {OpenSeadragon.Point} currentPos\n * The current pointer position, relative to the page including any scrolling.\n * @property {Number} currentTime\n * The current pointer contact time, in milliseconds.\n */\n\n\n /**\n * @class GesturePointList\n * @classdesc Provides an abstraction for a set of active {@link OpenSeadragon.MouseTracker.GesturePoint|GesturePoint} objects for a given pointer device type.\n * Active pointers are any pointer being tracked for this element which are in the hit-test area\n * of the element (for hover-capable devices) and/or have contact or a button press initiated in the element.\n * @memberof OpenSeadragon.MouseTracker\n * @param {String} type - The pointer device type: \"mouse\", \"touch\", \"pen\", etc.\n */\n $.MouseTracker.GesturePointList = function ( type ) {\n this._gPoints = [];\n /**\n * The pointer device type: \"mouse\", \"touch\", \"pen\", etc.\n * @member {String} type\n * @memberof OpenSeadragon.MouseTracker.GesturePointList#\n */\n this.type = type;\n /**\n * Current buttons pressed for the device.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @member {Number} buttons\n * @memberof OpenSeadragon.MouseTracker.GesturePointList#\n */\n this.buttons = 0;\n /**\n * Current number of contact points (touch points, mouse down, etc.) for the device.\n * @member {Number} contacts\n * @memberof OpenSeadragon.MouseTracker.GesturePointList#\n */\n this.contacts = 0;\n /**\n * Current number of clicks for the device. Used for multiple click gesture tracking.\n * @member {Number} clicks\n * @memberof OpenSeadragon.MouseTracker.GesturePointList#\n */\n this.clicks = 0;\n /**\n * Current number of captured pointers for the device.\n * @member {Number} captureCount\n * @memberof OpenSeadragon.MouseTracker.GesturePointList#\n */\n this.captureCount = 0;\n };\n\n /** @lends OpenSeadragon.MouseTracker.GesturePointList.prototype */\n $.MouseTracker.GesturePointList.prototype = {\n /**\n * @function\n * @returns {Number} Number of gesture points in the list.\n */\n getLength: function () {\n return this._gPoints.length;\n },\n /**\n * @function\n * @returns {Array.} The list of gesture points in the list as an array (read-only).\n */\n asArray: function () {\n return this._gPoints;\n },\n /**\n * @function\n * @param {OpenSeadragon.MouseTracker.GesturePoint} gesturePoint - A gesture point to add to the list.\n * @returns {Number} Number of gesture points in the list.\n */\n add: function ( gp ) {\n return this._gPoints.push( gp );\n },\n /**\n * @function\n * @param {Number} id - The id of the gesture point to remove from the list.\n * @returns {Number} Number of gesture points in the list.\n */\n removeById: function ( id ) {\n var i,\n len = this._gPoints.length;\n for ( i = 0; i < len; i++ ) {\n if ( this._gPoints[ i ].id === id ) {\n this._gPoints.splice( i, 1 );\n break;\n }\n }\n return this._gPoints.length;\n },\n /**\n * @function\n * @param {Number} index - The index of the gesture point to retrieve from the list.\n * @returns {OpenSeadragon.MouseTracker.GesturePoint|null} The gesture point at the given index, or null if not found.\n */\n getByIndex: function ( index ) {\n if ( index < this._gPoints.length) {\n return this._gPoints[ index ];\n }\n\n return null;\n },\n /**\n * @function\n * @param {Number} id - The id of the gesture point to retrieve from the list.\n * @returns {OpenSeadragon.MouseTracker.GesturePoint|null} The gesture point with the given id, or null if not found.\n */\n getById: function ( id ) {\n var i,\n len = this._gPoints.length;\n for ( i = 0; i < len; i++ ) {\n if ( this._gPoints[ i ].id === id ) {\n return this._gPoints[ i ];\n }\n }\n return null;\n },\n /**\n * @function\n * @returns {OpenSeadragon.MouseTracker.GesturePoint|null} The primary gesture point in the list, or null if not found.\n */\n getPrimary: function ( id ) {\n var i,\n len = this._gPoints.length;\n for ( i = 0; i < len; i++ ) {\n if ( this._gPoints[ i ].isPrimary ) {\n return this._gPoints[ i ];\n }\n }\n return null;\n },\n\n /**\n * Increment this pointer's contact count.\n * It will evaluate whether this pointer type is allowed to have multiple contacts.\n * @function\n */\n addContact: function() {\n ++this.contacts;\n\n if (this.contacts > 1 && (this.type === \"mouse\" || this.type === \"pen\")) {\n this.contacts = 1;\n }\n },\n\n /**\n * Decrement this pointer's contact count.\n * It will make sure the count does not go below 0.\n * @function\n */\n removeContact: function() {\n --this.contacts;\n\n if (this.contacts < 0) {\n this.contacts = 0;\n }\n }\n };\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Utility functions\n///////////////////////////////////////////////////////////////////////////////\n\n /**\n * Removes all tracked pointers.\n * @private\n * @inner\n */\n function clearTrackedPointers( tracker ) {\n var delegate = THIS[ tracker.hash ],\n i,\n pointerListCount = delegate.activePointersLists.length;\n\n for ( i = 0; i < pointerListCount; i++ ) {\n if ( delegate.activePointersLists[ i ].captureCount > 0 ) {\n $.removeEvent(\n $.MouseTracker.captureElement,\n 'mousemove',\n delegate.mousemovecaptured,\n true\n );\n $.removeEvent(\n $.MouseTracker.captureElement,\n 'mouseup',\n delegate.mouseupcaptured,\n true\n );\n $.removeEvent(\n $.MouseTracker.captureElement,\n $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove',\n delegate.pointermovecaptured,\n true\n );\n $.removeEvent(\n $.MouseTracker.captureElement,\n $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp',\n delegate.pointerupcaptured,\n true\n );\n $.removeEvent(\n $.MouseTracker.captureElement,\n 'touchmove',\n delegate.touchmovecaptured,\n true\n );\n $.removeEvent(\n $.MouseTracker.captureElement,\n 'touchend',\n delegate.touchendcaptured,\n true\n );\n\n delegate.activePointersLists[ i ].captureCount = 0;\n }\n }\n\n for ( i = 0; i < pointerListCount; i++ ) {\n delegate.activePointersLists.pop();\n }\n }\n\n /**\n * Starts tracking pointer events on the tracked element.\n * @private\n * @inner\n */\n function startTracking( tracker ) {\n var delegate = THIS[ tracker.hash ],\n event,\n i;\n\n if ( !delegate.tracking ) {\n for ( i = 0; i < $.MouseTracker.subscribeEvents.length; i++ ) {\n event = $.MouseTracker.subscribeEvents[ i ];\n $.addEvent(\n tracker.element,\n event,\n delegate[ event ],\n false\n );\n }\n\n clearTrackedPointers( tracker );\n\n delegate.tracking = true;\n }\n }\n\n /**\n * Stops tracking pointer events on the tracked element.\n * @private\n * @inner\n */\n function stopTracking( tracker ) {\n var delegate = THIS[ tracker.hash ],\n event,\n i;\n\n if ( delegate.tracking ) {\n for ( i = 0; i < $.MouseTracker.subscribeEvents.length; i++ ) {\n event = $.MouseTracker.subscribeEvents[ i ];\n $.removeEvent(\n tracker.element,\n event,\n delegate[ event ],\n false\n );\n }\n\n clearTrackedPointers( tracker );\n\n delegate.tracking = false;\n }\n }\n\n /**\n * @private\n * @inner\n */\n function getCaptureEventParams( tracker, pointerType ) {\n var delegate = THIS[ tracker.hash ];\n\n if ( pointerType === 'pointerevent' ) {\n return {\n upName: $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp',\n upHandler: delegate.pointerupcaptured,\n moveName: $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove',\n moveHandler: delegate.pointermovecaptured\n };\n } else if ( pointerType === 'mouse' ) {\n return {\n upName: 'mouseup',\n upHandler: delegate.mouseupcaptured,\n moveName: 'mousemove',\n moveHandler: delegate.mousemovecaptured\n };\n } else if ( pointerType === 'touch' ) {\n return {\n upName: 'touchend',\n upHandler: delegate.touchendcaptured,\n moveName: 'touchmove',\n moveHandler: delegate.touchmovecaptured\n };\n } else {\n throw new Error( \"MouseTracker.getCaptureEventParams: Unknown pointer type.\" );\n }\n }\n\n /**\n * Begin capturing pointer events to the tracked element.\n * @private\n * @inner\n */\n function capturePointer( tracker, pointerType, pointerCount ) {\n var pointsList = tracker.getActivePointersListByType( pointerType ),\n eventParams;\n\n pointsList.captureCount += (pointerCount || 1);\n\n if ( pointsList.captureCount === 1 ) {\n if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {\n tracker.element.setCapture( true );\n } else {\n eventParams = getCaptureEventParams( tracker, $.MouseTracker.havePointerEvents ? 'pointerevent' : pointerType );\n // We emulate mouse capture by hanging listeners on the document object.\n // (Note we listen on the capture phase so the captured handlers will get called first)\n // eslint-disable-next-line no-use-before-define\n if (isInIframe && canAccessEvents(window.top)) {\n $.addEvent(\n window.top,\n eventParams.upName,\n eventParams.upHandler,\n true\n );\n }\n $.addEvent(\n $.MouseTracker.captureElement,\n eventParams.upName,\n eventParams.upHandler,\n true\n );\n $.addEvent(\n $.MouseTracker.captureElement,\n eventParams.moveName,\n eventParams.moveHandler,\n true\n );\n }\n }\n }\n\n\n /**\n * Stop capturing pointer events to the tracked element.\n * @private\n * @inner\n */\n function releasePointer( tracker, pointerType, pointerCount ) {\n var pointsList = tracker.getActivePointersListByType( pointerType ),\n eventParams;\n\n pointsList.captureCount -= (pointerCount || 1);\n\n if ( pointsList.captureCount === 0 ) {\n if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {\n tracker.element.releaseCapture();\n } else {\n eventParams = getCaptureEventParams( tracker, $.MouseTracker.havePointerEvents ? 'pointerevent' : pointerType );\n // We emulate mouse capture by hanging listeners on the document object.\n // (Note we listen on the capture phase so the captured handlers will get called first)\n // eslint-disable-next-line no-use-before-define\n if (isInIframe && canAccessEvents(window.top)) {\n $.removeEvent(\n window.top,\n eventParams.upName,\n eventParams.upHandler,\n true\n );\n }\n $.removeEvent(\n $.MouseTracker.captureElement,\n eventParams.moveName,\n eventParams.moveHandler,\n true\n );\n $.removeEvent(\n $.MouseTracker.captureElement,\n eventParams.upName,\n eventParams.upHandler,\n true\n );\n }\n }\n }\n\n\n /**\n * Gets a W3C Pointer Events model compatible pointer type string from a DOM pointer event.\n * IE10 used a long integer value, but the W3C specification (and IE11+) use a string \"mouse\", \"touch\", \"pen\", etc.\n * @private\n * @inner\n */\n function getPointerType( event ) {\n var pointerTypeStr;\n if ( $.MouseTracker.unprefixedPointerEvents ) {\n pointerTypeStr = event.pointerType;\n } else {\n // IE10\n // MSPOINTER_TYPE_TOUCH: 0x00000002\n // MSPOINTER_TYPE_PEN: 0x00000003\n // MSPOINTER_TYPE_MOUSE: 0x00000004\n switch( event.pointerType )\n {\n case 0x00000002:\n pointerTypeStr = 'touch';\n break;\n case 0x00000003:\n pointerTypeStr = 'pen';\n break;\n case 0x00000004:\n pointerTypeStr = 'mouse';\n break;\n default:\n pointerTypeStr = '';\n }\n }\n return pointerTypeStr;\n }\n\n\n /**\n * @private\n * @inner\n */\n function getMouseAbsolute( event ) {\n return $.getMousePosition( event );\n }\n\n /**\n * @private\n * @inner\n */\n function getMouseRelative( event, element ) {\n return getPointRelativeToAbsolute( getMouseAbsolute( event ), element );\n }\n\n /**\n * @private\n * @inner\n */\n function getPointRelativeToAbsolute( point, element ) {\n var offset = $.getElementOffset( element );\n return point.minus( offset );\n }\n\n /**\n * @private\n * @inner\n */\n function getCenterPoint( point1, point2 ) {\n return new $.Point( ( point1.x + point2.x ) / 2, ( point1.y + point2.y ) / 2 );\n }\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Device-specific DOM event handlers\n///////////////////////////////////////////////////////////////////////////////\n\n /**\n * @private\n * @inner\n */\n function onClick( tracker, event ) {\n if ( tracker.clickHandler ) {\n $.cancelEvent( event );\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onDblClick( tracker, event ) {\n if ( tracker.dblClickHandler ) {\n $.cancelEvent( event );\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onKeyDown( tracker, event ) {\n //$.console.log( \"keydown %s %s %s %s %s\", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey );\n var propagate;\n if ( tracker.keyDownHandler ) {\n event = $.getEvent( event );\n propagate = tracker.keyDownHandler(\n {\n eventSource: tracker,\n keyCode: event.keyCode ? event.keyCode : event.charCode,\n ctrl: event.ctrlKey,\n shift: event.shiftKey,\n alt: event.altKey,\n meta: event.metaKey,\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( !propagate ) {\n $.cancelEvent( event );\n }\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onKeyUp( tracker, event ) {\n //$.console.log( \"keyup %s %s %s %s %s\", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey );\n var propagate;\n if ( tracker.keyUpHandler ) {\n event = $.getEvent( event );\n propagate = tracker.keyUpHandler(\n {\n eventSource: tracker,\n keyCode: event.keyCode ? event.keyCode : event.charCode,\n ctrl: event.ctrlKey,\n shift: event.shiftKey,\n alt: event.altKey,\n meta: event.metaKey,\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( !propagate ) {\n $.cancelEvent( event );\n }\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onKeyPress( tracker, event ) {\n //$.console.log( \"keypress %s %s %s %s %s\", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey );\n var propagate;\n if ( tracker.keyHandler ) {\n event = $.getEvent( event );\n propagate = tracker.keyHandler(\n {\n eventSource: tracker,\n keyCode: event.keyCode ? event.keyCode : event.charCode,\n ctrl: event.ctrlKey,\n shift: event.shiftKey,\n alt: event.altKey,\n meta: event.metaKey,\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( !propagate ) {\n $.cancelEvent( event );\n }\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onFocus( tracker, event ) {\n //console.log( \"focus %s\", event );\n var propagate;\n if ( tracker.focusHandler ) {\n event = $.getEvent( event );\n propagate = tracker.focusHandler(\n {\n eventSource: tracker,\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onBlur( tracker, event ) {\n //console.log( \"blur %s\", event );\n var propagate;\n if ( tracker.blurHandler ) {\n event = $.getEvent( event );\n propagate = tracker.blurHandler(\n {\n eventSource: tracker,\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n }\n\n\n /**\n * Handler for 'wheel' events\n *\n * @private\n * @inner\n */\n function onWheel( tracker, event ) {\n handleWheelEvent( tracker, event, event );\n }\n\n\n /**\n * Handler for 'mousewheel', 'DOMMouseScroll', and 'MozMousePixelScroll' events\n *\n * @private\n * @inner\n */\n function onMouseWheel( tracker, event ) {\n event = $.getEvent( event );\n\n // Simulate a 'wheel' event\n var simulatedEvent = {\n target: event.target || event.srcElement,\n type: \"wheel\",\n shiftKey: event.shiftKey || false,\n clientX: event.clientX,\n clientY: event.clientY,\n pageX: event.pageX ? event.pageX : event.clientX,\n pageY: event.pageY ? event.pageY : event.clientY,\n deltaMode: event.type == \"MozMousePixelScroll\" ? 0 : 1, // 0=pixel, 1=line, 2=page\n deltaX: 0,\n deltaZ: 0\n };\n\n // Calculate deltaY\n if ( $.MouseTracker.wheelEventName == \"mousewheel\" ) {\n simulatedEvent.deltaY = -event.wheelDelta / $.DEFAULT_SETTINGS.pixelsPerWheelLine;\n } else {\n simulatedEvent.deltaY = event.detail;\n }\n\n handleWheelEvent( tracker, simulatedEvent, event );\n }\n\n\n /**\n * Handles 'wheel' events.\n * The event may be simulated by the legacy mouse wheel event handler (onMouseWheel()).\n *\n * @private\n * @inner\n */\n function handleWheelEvent( tracker, event, originalEvent ) {\n var nDelta = 0,\n propagate;\n\n // The nDelta variable is gated to provide smooth z-index scrolling\n // since the mouse wheel allows for substantial deltas meant for rapid\n // y-index scrolling.\n // event.deltaMode: 0=pixel, 1=line, 2=page\n // TODO: Deltas in pixel mode should be accumulated then a scroll value computed after $.DEFAULT_SETTINGS.pixelsPerWheelLine threshold reached\n nDelta = event.deltaY < 0 ? 1 : -1;\n\n if ( tracker.scrollHandler ) {\n propagate = tracker.scrollHandler(\n {\n eventSource: tracker,\n pointerType: 'mouse',\n position: getMouseRelative( event, tracker.element ),\n scroll: nDelta,\n shift: event.shiftKey,\n isTouchEvent: false,\n originalEvent: originalEvent,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( originalEvent );\n }\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function isParentChild( parent, child )\n {\n if ( parent === child ) {\n return false;\n }\n while ( child && child !== parent ) {\n child = child.parentNode;\n }\n return child === parent;\n }\n\n\n /**\n * Only used on IE 8\n *\n * @private\n * @inner\n */\n function onMouseEnter( tracker, event ) {\n event = $.getEvent( event );\n\n handleMouseEnter( tracker, event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onMouseOver( tracker, event ) {\n event = $.getEvent( event );\n\n if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) {\n return;\n }\n\n handleMouseEnter( tracker, event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handleMouseEnter( tracker, event ) {\n var gPoint = {\n id: $.MouseTracker.mousePointerId,\n type: 'mouse',\n isPrimary: true,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n updatePointersEnter( tracker, event, [ gPoint ] );\n }\n\n\n /**\n * Only used on IE 8\n *\n * @private\n * @inner\n */\n function onMouseLeave( tracker, event ) {\n event = $.getEvent( event );\n\n handleMouseExit( tracker, event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onMouseOut( tracker, event ) {\n event = $.getEvent( event );\n\n if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) {\n return;\n }\n\n handleMouseExit( tracker, event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handleMouseExit( tracker, event ) {\n var gPoint = {\n id: $.MouseTracker.mousePointerId,\n type: 'mouse',\n isPrimary: true,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n updatePointersExit( tracker, event, [ gPoint ] );\n }\n\n\n /**\n * Returns a W3C DOM level 3 standard button value given an event.button property:\n * -1 == none, 0 == primary/left, 1 == middle, 2 == secondary/right, 3 == X1/back, 4 == X2/forward, 5 == eraser (pen)\n * @private\n * @inner\n */\n function getStandardizedButton( button ) {\n if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {\n // On IE 8, 0 == none, 1 == left, 2 == right, 3 == left and right, 4 == middle, 5 == left and middle, 6 == right and middle, 7 == all three\n // TODO: Support chorded (multiple) button presses on IE 8?\n if ( button === 1 ) {\n return 0;\n } else if ( button === 2 ) {\n return 2;\n } else if ( button === 4 ) {\n return 1;\n } else {\n return -1;\n }\n } else {\n return button;\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onMouseDown( tracker, event ) {\n var gPoint;\n\n event = $.getEvent( event );\n\n gPoint = {\n id: $.MouseTracker.mousePointerId,\n type: 'mouse',\n isPrimary: true,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n if ( updatePointersDown( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) {\n $.stopEvent( event );\n capturePointer( tracker, 'mouse' );\n }\n\n if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler ) {\n $.cancelEvent( event );\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onMouseUp( tracker, event ) {\n handleMouseUp( tracker, event );\n }\n\n /**\n * This handler is attached to the window object (on the capture phase) to emulate mouse capture.\n * onMouseUp is still attached to the tracked element, so stop propagation to avoid processing twice.\n *\n * @private\n * @inner\n */\n function onMouseUpCaptured( tracker, event ) {\n handleMouseUp( tracker, event );\n $.stopEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handleMouseUp( tracker, event ) {\n var gPoint;\n\n event = $.getEvent( event );\n\n gPoint = {\n id: $.MouseTracker.mousePointerId,\n type: 'mouse',\n isPrimary: true,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n if ( updatePointersUp( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) {\n releasePointer( tracker, 'mouse' );\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onMouseMove( tracker, event ) {\n handleMouseMove( tracker, event );\n }\n\n\n /**\n * This handler is attached to the window object (on the capture phase) to emulate mouse capture.\n * onMouseMove is still attached to the tracked element, so stop propagation to avoid processing twice.\n *\n * @private\n * @inner\n */\n function onMouseMoveCaptured( tracker, event ) {\n handleMouseMove( tracker, event );\n $.stopEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handleMouseMove( tracker, event ) {\n var gPoint;\n\n event = $.getEvent( event );\n\n gPoint = {\n id: $.MouseTracker.mousePointerId,\n type: 'mouse',\n isPrimary: true,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n updatePointersMove( tracker, event, [ gPoint ] );\n }\n\n\n /**\n * @private\n * @inner\n */\n function abortContacts( tracker, event, pointsList ) {\n var i,\n gPointCount = pointsList.getLength(),\n abortGPoints = [];\n\n // Check contact count for hoverable pointer types before aborting\n if (pointsList.type === 'touch' || pointsList.contacts > 0) {\n for ( i = 0; i < gPointCount; i++ ) {\n abortGPoints.push( pointsList.getByIndex( i ) );\n }\n\n if ( abortGPoints.length > 0 ) {\n // simulate touchend/mouseup\n updatePointersUp( tracker, event, abortGPoints, 0 ); // 0 means primary button press/release or touch contact\n // release pointer capture\n pointsList.captureCount = 1;\n releasePointer( tracker, pointsList.type );\n // simulate touchleave/mouseout\n updatePointersExit( tracker, event, abortGPoints );\n }\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onTouchStart( tracker, event ) {\n var time,\n i,\n j,\n touchCount = event.changedTouches.length,\n gPoints = [],\n parentGPoints,\n pointsList = tracker.getActivePointersListByType( 'touch' );\n\n time = $.now();\n\n if ( pointsList.getLength() > event.touches.length - touchCount ) {\n $.console.warn('Tracked touch contact count doesn\\'t match event.touches.length. Removing all tracked touch pointers.');\n abortContacts( tracker, event, pointsList );\n }\n\n for ( i = 0; i < touchCount; i++ ) {\n gPoints.push( {\n id: event.changedTouches[ i ].identifier,\n type: 'touch',\n // isPrimary not set - let the updatePointers functions determine it\n currentPos: getMouseAbsolute( event.changedTouches[ i ] ),\n currentTime: time\n } );\n }\n\n // simulate touchenter on our tracked element\n updatePointersEnter( tracker, event, gPoints );\n\n // simulate touchenter on our tracked element's tracked ancestor elements\n for ( i = 0; i < MOUSETRACKERS.length; i++ ) {\n if ( MOUSETRACKERS[ i ] !== tracker && MOUSETRACKERS[ i ].isTracking() && isParentChild( MOUSETRACKERS[ i ].element, tracker.element ) ) {\n parentGPoints = [];\n for ( j = 0; j < touchCount; j++ ) {\n parentGPoints.push( {\n id: event.changedTouches[ j ].identifier,\n type: 'touch',\n // isPrimary not set - let the updatePointers functions determine it\n currentPos: getMouseAbsolute( event.changedTouches[ j ] ),\n currentTime: time\n } );\n }\n updatePointersEnter( MOUSETRACKERS[ i ], event, parentGPoints );\n }\n }\n\n if ( updatePointersDown( tracker, event, gPoints, 0 ) ) { // 0 means primary button press/release or touch contact\n $.stopEvent( event );\n capturePointer( tracker, 'touch', touchCount );\n }\n\n $.cancelEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onTouchEnd( tracker, event ) {\n handleTouchEnd( tracker, event );\n }\n\n\n /**\n * This handler is attached to the window object (on the capture phase) to emulate pointer capture.\n * onTouchEnd is still attached to the tracked element, so stop propagation to avoid processing twice.\n *\n * @private\n * @inner\n */\n function onTouchEndCaptured( tracker, event ) {\n handleTouchEnd( tracker, event );\n $.stopEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handleTouchEnd( tracker, event ) {\n var time,\n i,\n j,\n touchCount = event.changedTouches.length,\n gPoints = [],\n parentGPoints;\n\n time = $.now();\n\n for ( i = 0; i < touchCount; i++ ) {\n gPoints.push( {\n id: event.changedTouches[ i ].identifier,\n type: 'touch',\n // isPrimary not set - let the updatePointers functions determine it\n currentPos: getMouseAbsolute( event.changedTouches[ i ] ),\n currentTime: time\n } );\n }\n\n if ( updatePointersUp( tracker, event, gPoints, 0 ) ) {\n releasePointer( tracker, 'touch', touchCount );\n }\n\n // simulate touchleave on our tracked element\n updatePointersExit( tracker, event, gPoints );\n\n // simulate touchleave on our tracked element's tracked ancestor elements\n for ( i = 0; i < MOUSETRACKERS.length; i++ ) {\n if ( MOUSETRACKERS[ i ] !== tracker && MOUSETRACKERS[ i ].isTracking() && isParentChild( MOUSETRACKERS[ i ].element, tracker.element ) ) {\n parentGPoints = [];\n for ( j = 0; j < touchCount; j++ ) {\n parentGPoints.push( {\n id: event.changedTouches[ j ].identifier,\n type: 'touch',\n // isPrimary not set - let the updatePointers functions determine it\n currentPos: getMouseAbsolute( event.changedTouches[ j ] ),\n currentTime: time\n } );\n }\n updatePointersExit( MOUSETRACKERS[ i ], event, parentGPoints );\n }\n }\n\n $.cancelEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onTouchMove( tracker, event ) {\n handleTouchMove( tracker, event );\n }\n\n\n /**\n * This handler is attached to the window object (on the capture phase) to emulate pointer capture.\n * onTouchMove is still attached to the tracked element, so stop propagation to avoid processing twice.\n *\n * @private\n * @inner\n */\n function onTouchMoveCaptured( tracker, event ) {\n handleTouchMove( tracker, event );\n $.stopEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handleTouchMove( tracker, event ) {\n var i,\n touchCount = event.changedTouches.length,\n gPoints = [];\n\n for ( i = 0; i < touchCount; i++ ) {\n gPoints.push( {\n id: event.changedTouches[ i ].identifier,\n type: 'touch',\n // isPrimary not set - let the updatePointers functions determine it\n currentPos: getMouseAbsolute( event.changedTouches[ i ] ),\n currentTime: $.now()\n } );\n }\n\n updatePointersMove( tracker, event, gPoints );\n\n $.cancelEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onTouchCancel( tracker, event ) {\n var pointsList = tracker.getActivePointersListByType('touch');\n\n abortContacts( tracker, event, pointsList );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onGestureStart( tracker, event ) {\n event.stopPropagation();\n event.preventDefault();\n return false;\n }\n\n\n /**\n * @private\n * @inner\n */\n function onGestureChange( tracker, event ) {\n event.stopPropagation();\n event.preventDefault();\n return false;\n }\n\n\n /**\n * @private\n * @inner\n */\n function onPointerOver( tracker, event ) {\n var gPoint;\n\n if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) {\n return;\n }\n\n gPoint = {\n id: event.pointerId,\n type: getPointerType( event ),\n isPrimary: event.isPrimary,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n updatePointersEnter( tracker, event, [ gPoint ] );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onPointerOut( tracker, event ) {\n var gPoint;\n\n if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) {\n return;\n }\n\n gPoint = {\n id: event.pointerId,\n type: getPointerType( event ),\n isPrimary: event.isPrimary,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n updatePointersExit( tracker, event, [ gPoint ] );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onPointerDown( tracker, event ) {\n var gPoint;\n\n gPoint = {\n id: event.pointerId,\n type: getPointerType( event ),\n isPrimary: event.isPrimary,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) {\n $.stopEvent( event );\n capturePointer( tracker, gPoint.type );\n }\n\n if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {\n $.cancelEvent( event );\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onPointerUp( tracker, event ) {\n handlePointerUp( tracker, event );\n }\n\n\n /**\n * This handler is attached to the window object (on the capture phase) to emulate mouse capture.\n * onPointerUp is still attached to the tracked element, so stop propagation to avoid processing twice.\n *\n * @private\n * @inner\n */\n function onPointerUpCaptured( tracker, event ) {\n var pointsList = tracker.getActivePointersListByType( getPointerType( event ) );\n if ( pointsList.getById( event.pointerId ) ) {\n handlePointerUp( tracker, event );\n }\n $.stopEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handlePointerUp( tracker, event ) {\n var gPoint;\n\n gPoint = {\n id: event.pointerId,\n type: getPointerType( event ),\n isPrimary: event.isPrimary,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) {\n releasePointer( tracker, gPoint.type );\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onPointerMove( tracker, event ) {\n handlePointerMove( tracker, event );\n }\n\n\n /**\n * This handler is attached to the window object (on the capture phase) to emulate mouse capture.\n * onPointerMove is still attached to the tracked element, so stop propagation to avoid processing twice.\n *\n * @private\n * @inner\n */\n function onPointerMoveCaptured( tracker, event ) {\n var pointsList = tracker.getActivePointersListByType( getPointerType( event ) );\n if ( pointsList.getById( event.pointerId ) ) {\n handlePointerMove( tracker, event );\n }\n $.stopEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handlePointerMove( tracker, event ) {\n // Pointer changed coordinates, button state, pressure, tilt, or contact geometry (e.g. width and height)\n var gPoint;\n\n gPoint = {\n id: event.pointerId,\n type: getPointerType( event ),\n isPrimary: event.isPrimary,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n updatePointersMove( tracker, event, [ gPoint ] );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onPointerCancel( tracker, event ) {\n var gPoint;\n\n gPoint = {\n id: event.pointerId,\n type: getPointerType( event )\n };\n\n updatePointersCancel( tracker, event, [ gPoint ] );\n }\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Device-agnostic DOM event handlers\n///////////////////////////////////////////////////////////////////////////////\n\n /**\n * @function\n * @private\n * @inner\n * @param {OpenSeadragon.MouseTracker.GesturePointList} pointsList\n * The GesturePointList to track the pointer in.\n * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint\n * Gesture point to track.\n * @returns {Number} Number of gesture points in pointsList.\n */\n function startTrackingPointer( pointsList, gPoint ) {\n\n // If isPrimary is not known for the pointer then set it according to our rules:\n // true if the first pointer in the gesture, otherwise false\n if ( !gPoint.hasOwnProperty( 'isPrimary' ) ) {\n if ( pointsList.getLength() === 0 ) {\n gPoint.isPrimary = true;\n } else {\n gPoint.isPrimary = false;\n }\n }\n gPoint.speed = 0;\n gPoint.direction = 0;\n gPoint.contactPos = gPoint.currentPos;\n gPoint.contactTime = gPoint.currentTime;\n gPoint.lastPos = gPoint.currentPos;\n gPoint.lastTime = gPoint.currentTime;\n\n return pointsList.add( gPoint );\n }\n\n\n /**\n * @function\n * @private\n * @inner\n * @param {OpenSeadragon.MouseTracker.GesturePointList} pointsList\n * The GesturePointList to stop tracking the pointer on.\n * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint\n * Gesture point to stop tracking.\n * @returns {Number} Number of gesture points in pointsList.\n */\n function stopTrackingPointer( pointsList, gPoint ) {\n var listLength,\n primaryPoint;\n\n if ( pointsList.getById( gPoint.id ) ) {\n listLength = pointsList.removeById( gPoint.id );\n\n // If isPrimary is not known for the pointer and we just removed the primary pointer from the list then we need to set another pointer as primary\n if ( !gPoint.hasOwnProperty( 'isPrimary' ) ) {\n primaryPoint = pointsList.getPrimary();\n if ( !primaryPoint ) {\n primaryPoint = pointsList.getByIndex( 0 );\n if ( primaryPoint ) {\n primaryPoint.isPrimary = true;\n }\n }\n }\n } else {\n listLength = pointsList.getLength();\n }\n\n return listLength;\n }\n\n\n /**\n * @function\n * @private\n * @inner\n * @param {OpenSeadragon.MouseTracker} tracker\n * A reference to the MouseTracker instance.\n * @param {Object} event\n * A reference to the originating DOM event.\n * @param {Array.} gPoints\n * Gesture points associated with the event.\n */\n function updatePointersEnter( tracker, event, gPoints ) {\n var pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),\n i,\n gPointCount = gPoints.length,\n curGPoint,\n updateGPoint,\n propagate;\n\n for ( i = 0; i < gPointCount; i++ ) {\n curGPoint = gPoints[ i ];\n updateGPoint = pointsList.getById( curGPoint.id );\n\n if ( updateGPoint ) {\n // Already tracking the pointer...update it\n updateGPoint.insideElement = true;\n updateGPoint.lastPos = updateGPoint.currentPos;\n updateGPoint.lastTime = updateGPoint.currentTime;\n updateGPoint.currentPos = curGPoint.currentPos;\n updateGPoint.currentTime = curGPoint.currentTime;\n\n curGPoint = updateGPoint;\n } else {\n // Initialize for tracking and add to the tracking list\n curGPoint.captured = false;\n curGPoint.insideElementPressed = false;\n curGPoint.insideElement = true;\n startTrackingPointer( pointsList, curGPoint );\n }\n\n // Enter\n if ( tracker.enterHandler ) {\n propagate = tracker.enterHandler(\n {\n eventSource: tracker,\n pointerType: curGPoint.type,\n position: getPointRelativeToAbsolute( curGPoint.currentPos, tracker.element ),\n buttons: pointsList.buttons,\n pointers: tracker.getActivePointerCount(),\n insideElementPressed: curGPoint.insideElementPressed,\n buttonDownAny: pointsList.buttons !== 0,\n isTouchEvent: curGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n }\n }\n\n\n /**\n * @function\n * @private\n * @inner\n * @param {OpenSeadragon.MouseTracker} tracker\n * A reference to the MouseTracker instance.\n * @param {Object} event\n * A reference to the originating DOM event.\n * @param {Array.} gPoints\n * Gesture points associated with the event.\n */\n function updatePointersExit( tracker, event, gPoints ) {\n var pointsList = tracker.getActivePointersListByType(gPoints[0].type),\n i,\n gPointCount = gPoints.length,\n curGPoint,\n updateGPoint,\n propagate;\n\n for ( i = 0; i < gPointCount; i++ ) {\n curGPoint = gPoints[ i ];\n updateGPoint = pointsList.getById( curGPoint.id );\n\n if ( updateGPoint ) {\n // Already tracking the pointer. If captured then update it, else stop tracking it\n if ( updateGPoint.captured ) {\n updateGPoint.insideElement = false;\n updateGPoint.lastPos = updateGPoint.currentPos;\n updateGPoint.lastTime = updateGPoint.currentTime;\n updateGPoint.currentPos = curGPoint.currentPos;\n updateGPoint.currentTime = curGPoint.currentTime;\n } else {\n stopTrackingPointer( pointsList, updateGPoint );\n }\n\n curGPoint = updateGPoint;\n }\n\n // Exit\n if ( tracker.exitHandler ) {\n propagate = tracker.exitHandler(\n {\n eventSource: tracker,\n pointerType: curGPoint.type,\n position: getPointRelativeToAbsolute( curGPoint.currentPos, tracker.element ),\n buttons: pointsList.buttons,\n pointers: tracker.getActivePointerCount(),\n insideElementPressed: updateGPoint ? updateGPoint.insideElementPressed : false,\n buttonDownAny: pointsList.buttons !== 0,\n isTouchEvent: curGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n }\n }\n\n\n /**\n * @function\n * @private\n * @inner\n * @param {OpenSeadragon.MouseTracker} tracker\n * A reference to the MouseTracker instance.\n * @param {Object} event\n * A reference to the originating DOM event.\n * @param {Array.} gPoints\n * Gesture points associated with the event.\n * @param {Number} buttonChanged\n * The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.\n * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model,\n * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events.\n *\n * @returns {Boolean} True if pointers should be captured to the tracked element, otherwise false.\n */\n function updatePointersDown( tracker, event, gPoints, buttonChanged ) {\n var delegate = THIS[ tracker.hash ],\n propagate,\n pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),\n i,\n gPointCount = gPoints.length,\n curGPoint,\n updateGPoint;\n\n if ( typeof event.buttons !== 'undefined' ) {\n pointsList.buttons = event.buttons;\n } else {\n if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {\n if ( buttonChanged === 0 ) {\n // Primary\n pointsList.buttons += 1;\n } else if ( buttonChanged === 1 ) {\n // Aux\n pointsList.buttons += 4;\n } else if ( buttonChanged === 2 ) {\n // Secondary\n pointsList.buttons += 2;\n } else if ( buttonChanged === 3 ) {\n // X1 (Back)\n pointsList.buttons += 8;\n } else if ( buttonChanged === 4 ) {\n // X2 (Forward)\n pointsList.buttons += 16;\n } else if ( buttonChanged === 5 ) {\n // Pen Eraser\n pointsList.buttons += 32;\n }\n } else {\n if ( buttonChanged === 0 ) {\n // Primary\n pointsList.buttons |= 1;\n } else if ( buttonChanged === 1 ) {\n // Aux\n pointsList.buttons |= 4;\n } else if ( buttonChanged === 2 ) {\n // Secondary\n pointsList.buttons |= 2;\n } else if ( buttonChanged === 3 ) {\n // X1 (Back)\n pointsList.buttons |= 8;\n } else if ( buttonChanged === 4 ) {\n // X2 (Forward)\n pointsList.buttons |= 16;\n } else if ( buttonChanged === 5 ) {\n // Pen Eraser\n pointsList.buttons |= 32;\n }\n }\n }\n\n // Some pointers may steal control from another pointer without firing the appropriate release events\n // e.g. Touching a screen while click-dragging with certain mice.\n var otherPointsLists = tracker.getActivePointersListsExceptType(gPoints[ 0 ].type);\n for (i = 0; i < otherPointsLists.length; i++) {\n //If another pointer has contact, simulate the release\n abortContacts(tracker, event, otherPointsLists[i]); // No-op if no active pointer\n }\n\n // Only capture and track primary button, pen, and touch contacts\n if ( buttonChanged !== 0 ) {\n // Aux Press\n if ( tracker.nonPrimaryPressHandler ) {\n propagate = tracker.nonPrimaryPressHandler(\n {\n eventSource: tracker,\n pointerType: gPoints[ 0 ].type,\n position: getPointRelativeToAbsolute( gPoints[ 0 ].currentPos, tracker.element ),\n button: buttonChanged,\n buttons: pointsList.buttons,\n isTouchEvent: gPoints[ 0 ].type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n\n return false;\n }\n\n for ( i = 0; i < gPointCount; i++ ) {\n curGPoint = gPoints[ i ];\n updateGPoint = pointsList.getById( curGPoint.id );\n\n if ( updateGPoint ) {\n // Already tracking the pointer...update it\n updateGPoint.captured = true;\n updateGPoint.insideElementPressed = true;\n updateGPoint.insideElement = true;\n updateGPoint.contactPos = curGPoint.currentPos;\n updateGPoint.contactTime = curGPoint.currentTime;\n updateGPoint.lastPos = updateGPoint.currentPos;\n updateGPoint.lastTime = updateGPoint.currentTime;\n updateGPoint.currentPos = curGPoint.currentPos;\n updateGPoint.currentTime = curGPoint.currentTime;\n\n curGPoint = updateGPoint;\n } else {\n // Initialize for tracking and add to the tracking list (no pointerover or pointermove event occurred before this)\n curGPoint.captured = true;\n curGPoint.insideElementPressed = true;\n curGPoint.insideElement = true;\n startTrackingPointer( pointsList, curGPoint );\n }\n\n pointsList.addContact();\n //$.console.log('contacts++ ', pointsList.contacts);\n\n if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {\n $.MouseTracker.gesturePointVelocityTracker.addPoint( tracker, curGPoint );\n }\n\n if ( pointsList.contacts === 1 ) {\n // Press\n if ( tracker.pressHandler ) {\n propagate = tracker.pressHandler(\n {\n eventSource: tracker,\n pointerType: curGPoint.type,\n position: getPointRelativeToAbsolute( curGPoint.contactPos, tracker.element ),\n buttons: pointsList.buttons,\n isTouchEvent: curGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n } else if ( pointsList.contacts === 2 ) {\n if ( tracker.pinchHandler && curGPoint.type === 'touch' ) {\n // Initialize for pinch\n delegate.pinchGPoints = pointsList.asArray();\n delegate.lastPinchDist = delegate.currentPinchDist = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos );\n delegate.lastPinchCenter = delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos );\n }\n }\n }\n\n return true;\n }\n\n\n /**\n * @function\n * @private\n * @inner\n * @param {OpenSeadragon.MouseTracker} tracker\n * A reference to the MouseTracker instance.\n * @param {Object} event\n * A reference to the originating DOM event.\n * @param {Array.} gPoints\n * Gesture points associated with the event.\n * @param {Number} buttonChanged\n * The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.\n * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model,\n * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events.\n *\n * @returns {Boolean} True if pointer capture should be released from the tracked element, otherwise false.\n */\n function updatePointersUp( tracker, event, gPoints, buttonChanged ) {\n var delegate = THIS[ tracker.hash ],\n pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),\n propagate,\n releasePoint,\n releaseTime,\n i,\n gPointCount = gPoints.length,\n curGPoint,\n updateGPoint,\n releaseCapture = false,\n wasCaptured = false,\n quick;\n\n if ( typeof event.buttons !== 'undefined' ) {\n pointsList.buttons = event.buttons;\n } else {\n if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {\n if ( buttonChanged === 0 ) {\n // Primary\n pointsList.buttons -= 1;\n } else if ( buttonChanged === 1 ) {\n // Aux\n pointsList.buttons -= 4;\n } else if ( buttonChanged === 2 ) {\n // Secondary\n pointsList.buttons -= 2;\n } else if ( buttonChanged === 3 ) {\n // X1 (Back)\n pointsList.buttons -= 8;\n } else if ( buttonChanged === 4 ) {\n // X2 (Forward)\n pointsList.buttons -= 16;\n } else if ( buttonChanged === 5 ) {\n // Pen Eraser\n pointsList.buttons -= 32;\n }\n } else {\n if ( buttonChanged === 0 ) {\n // Primary\n pointsList.buttons ^= ~1;\n } else if ( buttonChanged === 1 ) {\n // Aux\n pointsList.buttons ^= ~4;\n } else if ( buttonChanged === 2 ) {\n // Secondary\n pointsList.buttons ^= ~2;\n } else if ( buttonChanged === 3 ) {\n // X1 (Back)\n pointsList.buttons ^= ~8;\n } else if ( buttonChanged === 4 ) {\n // X2 (Forward)\n pointsList.buttons ^= ~16;\n } else if ( buttonChanged === 5 ) {\n // Pen Eraser\n pointsList.buttons ^= ~32;\n }\n }\n }\n\n // Only capture and track primary button, pen, and touch contacts\n if ( buttonChanged !== 0 ) {\n // Aux Release\n if ( tracker.nonPrimaryReleaseHandler ) {\n propagate = tracker.nonPrimaryReleaseHandler(\n {\n eventSource: tracker,\n pointerType: gPoints[ 0 ].type,\n position: getPointRelativeToAbsolute(gPoints[0].currentPos, tracker.element),\n button: buttonChanged,\n buttons: pointsList.buttons,\n isTouchEvent: gPoints[ 0 ].type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n\n // A primary mouse button may have been released while the non-primary button was down\n var otherPointsList = tracker.getActivePointersListByType(\"mouse\");\n // Stop tracking the mouse; see https://github.com/openseadragon/openseadragon/pull/1223\n abortContacts(tracker, event, otherPointsList); // No-op if no active pointer\n\n return false;\n }\n\n for ( i = 0; i < gPointCount; i++ ) {\n curGPoint = gPoints[ i ];\n updateGPoint = pointsList.getById( curGPoint.id );\n\n if ( updateGPoint ) {\n // Update the pointer, stop tracking it if not still in this element\n if ( updateGPoint.captured ) {\n updateGPoint.captured = false;\n releaseCapture = true;\n wasCaptured = true;\n }\n updateGPoint.lastPos = updateGPoint.currentPos;\n updateGPoint.lastTime = updateGPoint.currentTime;\n updateGPoint.currentPos = curGPoint.currentPos;\n updateGPoint.currentTime = curGPoint.currentTime;\n if ( !updateGPoint.insideElement ) {\n stopTrackingPointer( pointsList, updateGPoint );\n }\n\n releasePoint = updateGPoint.currentPos;\n releaseTime = updateGPoint.currentTime;\n\n if ( wasCaptured ) {\n // Pointer was activated in our element but could have been removed in any element since events are captured to our element\n\n pointsList.removeContact();\n //$.console.log('contacts-- ', pointsList.contacts);\n\n if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {\n $.MouseTracker.gesturePointVelocityTracker.removePoint( tracker, updateGPoint );\n }\n\n if ( pointsList.contacts === 0 ) {\n\n // Release (pressed in our element)\n if ( tracker.releaseHandler ) {\n propagate = tracker.releaseHandler(\n {\n eventSource: tracker,\n pointerType: updateGPoint.type,\n position: getPointRelativeToAbsolute( releasePoint, tracker.element ),\n buttons: pointsList.buttons,\n insideElementPressed: updateGPoint.insideElementPressed,\n insideElementReleased: updateGPoint.insideElement,\n isTouchEvent: updateGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n\n // Drag End\n if ( tracker.dragEndHandler && !updateGPoint.currentPos.equals( updateGPoint.contactPos ) ) {\n propagate = tracker.dragEndHandler(\n {\n eventSource: tracker,\n pointerType: updateGPoint.type,\n position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),\n speed: updateGPoint.speed,\n direction: updateGPoint.direction,\n shift: event.shiftKey,\n isTouchEvent: updateGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n\n // Click / Double-Click\n if ( ( tracker.clickHandler || tracker.dblClickHandler ) && updateGPoint.insideElement ) {\n quick = releaseTime - updateGPoint.contactTime <= tracker.clickTimeThreshold &&\n updateGPoint.contactPos.distanceTo( releasePoint ) <= tracker.clickDistThreshold;\n\n // Click\n if ( tracker.clickHandler ) {\n propagate = tracker.clickHandler(\n {\n eventSource: tracker,\n pointerType: updateGPoint.type,\n position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),\n quick: quick,\n shift: event.shiftKey,\n isTouchEvent: updateGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n\n // Double-Click\n if ( tracker.dblClickHandler && quick ) {\n pointsList.clicks++;\n if ( pointsList.clicks === 1 ) {\n delegate.lastClickPos = releasePoint;\n /*jshint loopfunc:true*/\n delegate.dblClickTimeOut = setTimeout( function() {\n pointsList.clicks = 0;\n }, tracker.dblClickTimeThreshold );\n /*jshint loopfunc:false*/\n } else if ( pointsList.clicks === 2 ) {\n clearTimeout( delegate.dblClickTimeOut );\n pointsList.clicks = 0;\n if ( delegate.lastClickPos.distanceTo( releasePoint ) <= tracker.dblClickDistThreshold ) {\n propagate = tracker.dblClickHandler(\n {\n eventSource: tracker,\n pointerType: updateGPoint.type,\n position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),\n shift: event.shiftKey,\n isTouchEvent: updateGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n delegate.lastClickPos = null;\n }\n }\n }\n } else if ( pointsList.contacts === 2 ) {\n if ( tracker.pinchHandler && updateGPoint.type === 'touch' ) {\n // Reset for pinch\n delegate.pinchGPoints = pointsList.asArray();\n delegate.lastPinchDist = delegate.currentPinchDist = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos );\n delegate.lastPinchCenter = delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos );\n }\n }\n } else {\n // Pointer was activated in another element but removed in our element\n\n // Release (pressed in another element)\n if ( tracker.releaseHandler ) {\n propagate = tracker.releaseHandler(\n {\n eventSource: tracker,\n pointerType: updateGPoint.type,\n position: getPointRelativeToAbsolute( releasePoint, tracker.element ),\n buttons: pointsList.buttons,\n insideElementPressed: updateGPoint.insideElementPressed,\n insideElementReleased: updateGPoint.insideElement,\n isTouchEvent: updateGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n }\n }\n }\n\n return releaseCapture;\n }\n\n\n /**\n * Call when pointer(s) change coordinates, button state, pressure, tilt, or contact geometry (e.g. width and height)\n *\n * @function\n * @private\n * @inner\n * @param {OpenSeadragon.MouseTracker} tracker\n * A reference to the MouseTracker instance.\n * @param {Object} event\n * A reference to the originating DOM event.\n * @param {Array.} gPoints\n * Gesture points associated with the event.\n */\n function updatePointersMove( tracker, event, gPoints ) {\n var delegate = THIS[ tracker.hash ],\n pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),\n i,\n gPointCount = gPoints.length,\n curGPoint,\n updateGPoint,\n gPointArray,\n delta,\n propagate;\n\n if ( typeof event.buttons !== 'undefined' ) {\n pointsList.buttons = event.buttons;\n }\n\n for ( i = 0; i < gPointCount; i++ ) {\n curGPoint = gPoints[ i ];\n updateGPoint = pointsList.getById( curGPoint.id );\n\n if ( updateGPoint ) {\n // Already tracking the pointer...update it\n if ( curGPoint.hasOwnProperty( 'isPrimary' ) ) {\n updateGPoint.isPrimary = curGPoint.isPrimary;\n }\n updateGPoint.lastPos = updateGPoint.currentPos;\n updateGPoint.lastTime = updateGPoint.currentTime;\n updateGPoint.currentPos = curGPoint.currentPos;\n updateGPoint.currentTime = curGPoint.currentTime;\n } else {\n // Initialize for tracking and add to the tracking list (no pointerover or pointerdown event occurred before this)\n curGPoint.captured = false;\n curGPoint.insideElementPressed = false;\n curGPoint.insideElement = true;\n startTrackingPointer( pointsList, curGPoint );\n }\n }\n\n // Stop (mouse only)\n if ( tracker.stopHandler && gPoints[ 0 ].type === 'mouse' ) {\n clearTimeout( tracker.stopTimeOut );\n tracker.stopTimeOut = setTimeout( function() {\n handlePointerStop( tracker, event, gPoints[ 0 ].type );\n }, tracker.stopDelay );\n }\n\n if ( pointsList.contacts === 0 ) {\n // Move (no contacts: hovering mouse or other hover-capable device)\n if ( tracker.moveHandler ) {\n propagate = tracker.moveHandler(\n {\n eventSource: tracker,\n pointerType: gPoints[ 0 ].type,\n position: getPointRelativeToAbsolute( gPoints[ 0 ].currentPos, tracker.element ),\n buttons: pointsList.buttons,\n isTouchEvent: gPoints[ 0 ].type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n } else if ( pointsList.contacts === 1 ) {\n // Move (1 contact)\n if ( tracker.moveHandler ) {\n updateGPoint = pointsList.asArray()[ 0 ];\n propagate = tracker.moveHandler(\n {\n eventSource: tracker,\n pointerType: updateGPoint.type,\n position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),\n buttons: pointsList.buttons,\n isTouchEvent: updateGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n\n // Drag\n if ( tracker.dragHandler ) {\n updateGPoint = pointsList.asArray()[ 0 ];\n delta = updateGPoint.currentPos.minus( updateGPoint.lastPos );\n propagate = tracker.dragHandler(\n {\n eventSource: tracker,\n pointerType: updateGPoint.type,\n position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),\n buttons: pointsList.buttons,\n delta: delta,\n speed: updateGPoint.speed,\n direction: updateGPoint.direction,\n shift: event.shiftKey,\n isTouchEvent: updateGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n } else if ( pointsList.contacts === 2 ) {\n // Move (2 contacts, use center)\n if ( tracker.moveHandler ) {\n gPointArray = pointsList.asArray();\n propagate = tracker.moveHandler(\n {\n eventSource: tracker,\n pointerType: gPointArray[ 0 ].type,\n position: getPointRelativeToAbsolute( getCenterPoint( gPointArray[ 0 ].currentPos, gPointArray[ 1 ].currentPos ), tracker.element ),\n buttons: pointsList.buttons,\n isTouchEvent: gPointArray[ 0 ].type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n\n // Pinch\n if ( tracker.pinchHandler && gPoints[ 0 ].type === 'touch' ) {\n delta = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos );\n if ( delta != delegate.currentPinchDist ) {\n delegate.lastPinchDist = delegate.currentPinchDist;\n delegate.currentPinchDist = delta;\n delegate.lastPinchCenter = delegate.currentPinchCenter;\n delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos );\n propagate = tracker.pinchHandler(\n {\n eventSource: tracker,\n pointerType: 'touch',\n gesturePoints: delegate.pinchGPoints,\n lastCenter: getPointRelativeToAbsolute( delegate.lastPinchCenter, tracker.element ),\n center: getPointRelativeToAbsolute( delegate.currentPinchCenter, tracker.element ),\n lastDistance: delegate.lastPinchDist,\n distance: delegate.currentPinchDist,\n shift: event.shiftKey,\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n }\n }\n }\n\n\n /**\n * @function\n * @private\n * @inner\n * @param {OpenSeadragon.MouseTracker} tracker\n * A reference to the MouseTracker instance.\n * @param {Object} event\n * A reference to the originating DOM event.\n * @param {Array.} gPoints\n * Gesture points associated with the event.\n */\n function updatePointersCancel( tracker, event, gPoints ) {\n updatePointersUp( tracker, event, gPoints, 0 );\n updatePointersExit( tracker, event, gPoints );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handlePointerStop( tracker, originalMoveEvent, pointerType ) {\n if ( tracker.stopHandler ) {\n tracker.stopHandler( {\n eventSource: tracker,\n pointerType: pointerType,\n position: getMouseRelative( originalMoveEvent, tracker.element ),\n buttons: tracker.getActivePointersListByType( pointerType ).buttons,\n isTouchEvent: pointerType === 'touch',\n originalEvent: originalMoveEvent,\n preventDefaultAction: false,\n userData: tracker.userData\n } );\n }\n }\n\n /**\n * True if inside an iframe, otherwise false.\n * @member {Boolean} isInIframe\n * @private\n * @inner\n */\n var isInIframe = (function() {\n try {\n return window.self !== window.top;\n } catch (e) {\n return true;\n }\n })();\n\n /**\n * @function\n * @private\n * @inner\n * @returns {Boolean} True if the target has access rights to events, otherwise false.\n */\n function canAccessEvents (target) {\n try {\n return target.addEventListener && target.removeEventListener;\n } catch (e) {\n return false;\n }\n }\n\n}(OpenSeadragon));\n","/*\n * OpenSeadragon - Control\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * An enumeration of supported locations where controls can be anchored.\n * The anchoring is always relative to the container.\n * @member ControlAnchor\n * @memberof OpenSeadragon\n * @static\n * @type {Object}\n * @property {Number} NONE\n * @property {Number} TOP_LEFT\n * @property {Number} TOP_RIGHT\n * @property {Number} BOTTOM_LEFT\n * @property {Number} BOTTOM_RIGHT\n * @property {Number} ABSOLUTE\n */\n$.ControlAnchor = {\n NONE: 0,\n TOP_LEFT: 1,\n TOP_RIGHT: 2,\n BOTTOM_RIGHT: 3,\n BOTTOM_LEFT: 4,\n ABSOLUTE: 5\n};\n\n/**\n * @class Control\n * @classdesc A Control represents any interface element which is meant to allow the user\n * to interact with the zoomable interface. Any control can be anchored to any\n * element.\n *\n * @memberof OpenSeadragon\n * @param {Element} element - the control element to be anchored in the container.\n * @param {Object } options - All required and optional settings for configuring a control element.\n * @param {OpenSeadragon.ControlAnchor} [options.anchor=OpenSeadragon.ControlAnchor.NONE] - the position of the control\n * relative to the container.\n * @param {Boolean} [options.attachToViewer=true] - Whether the control should be added directly to the viewer, or\n * directly to the container\n * @param {Boolean} [options.autoFade=true] - Whether the control should have the autofade behavior\n * @param {Element} container - the element to control will be anchored too.\n */\n$.Control = function ( element, options, container ) {\n var parent = element.parentNode;\n if (typeof options === 'number')\n {\n $.console.error(\"Passing an anchor directly into the OpenSeadragon.Control constructor is deprecated; \" +\n \"please use an options object instead. \" +\n \"Support for this deprecated variant is scheduled for removal in December 2013\");\n options = {anchor: options};\n }\n options.attachToViewer = (typeof options.attachToViewer === 'undefined') ? true : options.attachToViewer;\n /**\n * True if the control should have autofade behavior.\n * @member {Boolean} autoFade\n * @memberof OpenSeadragon.Control#\n */\n this.autoFade = (typeof options.autoFade === 'undefined') ? true : options.autoFade;\n /**\n * The element providing the user interface with some type of control (e.g. a zoom-in button).\n * @member {Element} element\n * @memberof OpenSeadragon.Control#\n */\n this.element = element;\n /**\n * The position of the Control relative to its container.\n * @member {OpenSeadragon.ControlAnchor} anchor\n * @memberof OpenSeadragon.Control#\n */\n this.anchor = options.anchor;\n /**\n * The Control's containing element.\n * @member {Element} container\n * @memberof OpenSeadragon.Control#\n */\n this.container = container;\n /**\n * A neutral element surrounding the control element.\n * @member {Element} wrapper\n * @memberof OpenSeadragon.Control#\n */\n if ( this.anchor == $.ControlAnchor.ABSOLUTE ) {\n this.wrapper = $.makeNeutralElement( \"div\" );\n this.wrapper.style.position = \"absolute\";\n this.wrapper.style.top = typeof (options.top) == \"number\" ? (options.top + 'px') : options.top;\n this.wrapper.style.left = typeof (options.left) == \"number\" ? (options.left + 'px') : options.left;\n this.wrapper.style.height = typeof (options.height) == \"number\" ? (options.height + 'px') : options.height;\n this.wrapper.style.width = typeof (options.width) == \"number\" ? (options.width + 'px') : options.width;\n this.wrapper.style.margin = \"0px\";\n this.wrapper.style.padding = \"0px\";\n\n this.element.style.position = \"relative\";\n this.element.style.top = \"0px\";\n this.element.style.left = \"0px\";\n this.element.style.height = \"100%\";\n this.element.style.width = \"100%\";\n } else {\n this.wrapper = $.makeNeutralElement( \"div\" );\n this.wrapper.style.display = \"inline-block\";\n if ( this.anchor == $.ControlAnchor.NONE ) {\n // IE6 fix\n this.wrapper.style.width = this.wrapper.style.height = \"100%\";\n }\n }\n this.wrapper.appendChild( this.element );\n\n if (options.attachToViewer ) {\n if ( this.anchor == $.ControlAnchor.TOP_RIGHT ||\n this.anchor == $.ControlAnchor.BOTTOM_RIGHT ) {\n this.container.insertBefore(\n this.wrapper,\n this.container.firstChild\n );\n } else {\n this.container.appendChild( this.wrapper );\n }\n } else {\n parent.appendChild( this.wrapper );\n }\n};\n\n/** @lends OpenSeadragon.Control.prototype */\n$.Control.prototype = {\n\n /**\n * Removes the control from the container.\n * @function\n */\n destroy: function() {\n this.wrapper.removeChild( this.element );\n this.container.removeChild( this.wrapper );\n },\n\n /**\n * Determines if the control is currently visible.\n * @function\n * @return {Boolean} true if currenly visible, false otherwise.\n */\n isVisible: function() {\n return this.wrapper.style.display != \"none\";\n },\n\n /**\n * Toggles the visibility of the control.\n * @function\n * @param {Boolean} visible - true to make visible, false to hide.\n */\n setVisible: function( visible ) {\n this.wrapper.style.display = visible ?\n ( this.anchor == $.ControlAnchor.ABSOLUTE ? 'block' : 'inline-block' ) :\n \"none\";\n },\n\n /**\n * Sets the opacity level for the control.\n * @function\n * @param {Number} opactiy - a value between 1 and 0 inclusively.\n */\n setOpacity: function( opacity ) {\n if ( this.element[ $.SIGNAL ] && $.Browser.vendor == $.BROWSERS.IE ) {\n $.setElementOpacity( this.element, opacity, true );\n } else {\n $.setElementOpacity( this.wrapper, opacity, true );\n }\n }\n};\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - ControlDock\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n /**\n * @class ControlDock\n * @classdesc Provides a container element (a <form> element) with support for the layout of control elements.\n *\n * @memberof OpenSeadragon\n */\n $.ControlDock = function( options ){\n var layouts = [ 'topleft', 'topright', 'bottomright', 'bottomleft'],\n layout,\n i;\n\n $.extend( true, this, {\n id: 'controldock-' + $.now() + '-' + Math.floor(Math.random() * 1000000),\n container: $.makeNeutralElement( 'div' ),\n controls: []\n }, options );\n\n // Disable the form's submit; otherwise button clicks and return keys\n // can trigger it.\n this.container.onsubmit = function() {\n return false;\n };\n\n if( this.element ){\n this.element = $.getElement( this.element );\n this.element.appendChild( this.container );\n this.element.style.position = 'relative';\n this.container.style.width = '100%';\n this.container.style.height = '100%';\n }\n\n for( i = 0; i < layouts.length; i++ ){\n layout = layouts[ i ];\n this.controls[ layout ] = $.makeNeutralElement( \"div\" );\n this.controls[ layout ].style.position = 'absolute';\n if ( layout.match( 'left' ) ){\n this.controls[ layout ].style.left = '0px';\n }\n if ( layout.match( 'right' ) ){\n this.controls[ layout ].style.right = '0px';\n }\n if ( layout.match( 'top' ) ){\n this.controls[ layout ].style.top = '0px';\n }\n if ( layout.match( 'bottom' ) ){\n this.controls[ layout ].style.bottom = '0px';\n }\n }\n\n this.container.appendChild( this.controls.topleft );\n this.container.appendChild( this.controls.topright );\n this.container.appendChild( this.controls.bottomright );\n this.container.appendChild( this.controls.bottomleft );\n };\n\n /** @lends OpenSeadragon.ControlDock.prototype */\n $.ControlDock.prototype = {\n\n /**\n * @function\n */\n addControl: function ( element, controlOptions ) {\n element = $.getElement( element );\n var div = null;\n\n if ( getControlIndex( this, element ) >= 0 ) {\n return; // they're trying to add a duplicate control\n }\n\n switch ( controlOptions.anchor ) {\n case $.ControlAnchor.TOP_RIGHT:\n div = this.controls.topright;\n element.style.position = \"relative\";\n element.style.paddingRight = \"0px\";\n element.style.paddingTop = \"0px\";\n break;\n case $.ControlAnchor.BOTTOM_RIGHT:\n div = this.controls.bottomright;\n element.style.position = \"relative\";\n element.style.paddingRight = \"0px\";\n element.style.paddingBottom = \"0px\";\n break;\n case $.ControlAnchor.BOTTOM_LEFT:\n div = this.controls.bottomleft;\n element.style.position = \"relative\";\n element.style.paddingLeft = \"0px\";\n element.style.paddingBottom = \"0px\";\n break;\n case $.ControlAnchor.TOP_LEFT:\n div = this.controls.topleft;\n element.style.position = \"relative\";\n element.style.paddingLeft = \"0px\";\n element.style.paddingTop = \"0px\";\n break;\n case $.ControlAnchor.ABSOLUTE:\n div = this.container;\n element.style.margin = \"0px\";\n element.style.padding = \"0px\";\n break;\n default:\n case $.ControlAnchor.NONE:\n div = this.container;\n element.style.margin = \"0px\";\n element.style.padding = \"0px\";\n break;\n }\n\n this.controls.push(\n new $.Control( element, controlOptions, div )\n );\n element.style.display = \"inline-block\";\n },\n\n\n /**\n * @function\n * @return {OpenSeadragon.ControlDock} Chainable.\n */\n removeControl: function ( element ) {\n element = $.getElement( element );\n var i = getControlIndex( this, element );\n\n if ( i >= 0 ) {\n this.controls[ i ].destroy();\n this.controls.splice( i, 1 );\n }\n\n return this;\n },\n\n /**\n * @function\n * @return {OpenSeadragon.ControlDock} Chainable.\n */\n clearControls: function () {\n while ( this.controls.length > 0 ) {\n this.controls.pop().destroy();\n }\n\n return this;\n },\n\n\n /**\n * @function\n * @return {Boolean}\n */\n areControlsEnabled: function () {\n var i;\n\n for ( i = this.controls.length - 1; i >= 0; i-- ) {\n if ( this.controls[ i ].isVisible() ) {\n return true;\n }\n }\n\n return false;\n },\n\n\n /**\n * @function\n * @return {OpenSeadragon.ControlDock} Chainable.\n */\n setControlsEnabled: function( enabled ) {\n var i;\n\n for ( i = this.controls.length - 1; i >= 0; i-- ) {\n this.controls[ i ].setVisible( enabled );\n }\n\n return this;\n }\n\n };\n\n\n ///////////////////////////////////////////////////////////////////////////////\n // Utility methods\n ///////////////////////////////////////////////////////////////////////////////\n function getControlIndex( dock, element ) {\n var controls = dock.controls,\n i;\n\n for ( i = controls.length - 1; i >= 0; i-- ) {\n if ( controls[ i ].element == element ) {\n return i;\n }\n }\n\n return -1;\n }\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - Placement\n *\n * Copyright (C) 2010-2016 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function($) {\n\n /**\n * An enumeration of positions to anchor an element.\n * @member Placement\n * @memberOf OpenSeadragon\n * @static\n * @readonly\n * @property {OpenSeadragon.Placement} CENTER\n * @property {OpenSeadragon.Placement} TOP_LEFT\n * @property {OpenSeadragon.Placement} TOP\n * @property {OpenSeadragon.Placement} TOP_RIGHT\n * @property {OpenSeadragon.Placement} RIGHT\n * @property {OpenSeadragon.Placement} BOTTOM_RIGHT\n * @property {OpenSeadragon.Placement} BOTTOM\n * @property {OpenSeadragon.Placement} BOTTOM_LEFT\n * @property {OpenSeadragon.Placement} LEFT\n */\n $.Placement = $.freezeObject({\n CENTER: 0,\n TOP_LEFT: 1,\n TOP: 2,\n TOP_RIGHT: 3,\n RIGHT: 4,\n BOTTOM_RIGHT: 5,\n BOTTOM: 6,\n BOTTOM_LEFT: 7,\n LEFT: 8,\n properties: {\n 0: {\n isLeft: false,\n isHorizontallyCentered: true,\n isRight: false,\n isTop: false,\n isVerticallyCentered: true,\n isBottom: false\n },\n 1: {\n isLeft: true,\n isHorizontallyCentered: false,\n isRight: false,\n isTop: true,\n isVerticallyCentered: false,\n isBottom: false\n },\n 2: {\n isLeft: false,\n isHorizontallyCentered: true,\n isRight: false,\n isTop: true,\n isVerticallyCentered: false,\n isBottom: false\n },\n 3: {\n isLeft: false,\n isHorizontallyCentered: false,\n isRight: true,\n isTop: true,\n isVerticallyCentered: false,\n isBottom: false\n },\n 4: {\n isLeft: false,\n isHorizontallyCentered: false,\n isRight: true,\n isTop: false,\n isVerticallyCentered: true,\n isBottom: false\n },\n 5: {\n isLeft: false,\n isHorizontallyCentered: false,\n isRight: true,\n isTop: false,\n isVerticallyCentered: false,\n isBottom: true\n },\n 6: {\n isLeft: false,\n isHorizontallyCentered: true,\n isRight: false,\n isTop: false,\n isVerticallyCentered: false,\n isBottom: true\n },\n 7: {\n isLeft: true,\n isHorizontallyCentered: false,\n isRight: false,\n isTop: false,\n isVerticallyCentered: false,\n isBottom: true\n },\n 8: {\n isLeft: true,\n isHorizontallyCentered: false,\n isRight: false,\n isTop: false,\n isVerticallyCentered: true,\n isBottom: false\n }\n }\n });\n\n}(OpenSeadragon));\n","/*\n * OpenSeadragon - Viewer\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n// dictionary from hash to private properties\nvar THIS = {};\nvar nextHash = 1;\n\n/**\n *\n * The main point of entry into creating a zoomable image on the page.
      \n *
      \n * We have provided an idiomatic javascript constructor which takes\n * a single object, but still support the legacy positional arguments.
      \n *
      \n * The options below are given in order that they appeared in the constructor\n * as arguments and we translate a positional call into an idiomatic call.
      \n *
      \n * To create a viewer, you can use either of this methods:
      \n *
        \n *
      • var viewer = new OpenSeadragon.Viewer(options);
      • \n *
      • var viewer = OpenSeadragon(options);
      • \n *
      \n * @class Viewer\n * @classdesc The main OpenSeadragon viewer class.\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.EventSource\n * @extends OpenSeadragon.ControlDock\n * @param {OpenSeadragon.Options} options - Viewer options.\n *\n **/\n$.Viewer = function( options ) {\n\n var args = arguments,\n _this = this,\n i;\n\n\n //backward compatibility for positional args while prefering more\n //idiomatic javascript options object as the only argument\n if( !$.isPlainObject( options ) ){\n options = {\n id: args[ 0 ],\n xmlPath: args.length > 1 ? args[ 1 ] : undefined,\n prefixUrl: args.length > 2 ? args[ 2 ] : undefined,\n controls: args.length > 3 ? args[ 3 ] : undefined,\n overlays: args.length > 4 ? args[ 4 ] : undefined\n };\n }\n\n //options.config and the general config argument are deprecated\n //in favor of the more direct specification of optional settings\n //being pass directly on the options object\n if ( options.config ){\n $.extend( true, options, options.config );\n delete options.config;\n }\n\n //Public properties\n //Allow the options object to override global defaults\n $.extend( true, this, {\n\n //internal state and dom identifiers\n id: options.id,\n hash: options.hash || nextHash++,\n /**\n * Index for page to be shown first next time open() is called (only used in sequenceMode).\n * @member {Number} initialPage\n * @memberof OpenSeadragon.Viewer#\n */\n initialPage: 0,\n\n //dom nodes\n /**\n * The parent element of this Viewer instance, passed in when the Viewer was created.\n * @member {Element} element\n * @memberof OpenSeadragon.Viewer#\n */\n element: null,\n /**\n * A <div> element (provided by {@link OpenSeadragon.ControlDock}), the base element of this Viewer instance.

      \n * Child element of {@link OpenSeadragon.Viewer#element}.\n * @member {Element} container\n * @memberof OpenSeadragon.Viewer#\n */\n container: null,\n /**\n * A <div> element, the element where user-input events are handled for panning and zooming.

      \n * Child element of {@link OpenSeadragon.Viewer#container},\n * positioned on top of {@link OpenSeadragon.Viewer#keyboardCommandArea}.

      \n * The parent of {@link OpenSeadragon.Drawer#canvas} instances.\n * @member {Element} canvas\n * @memberof OpenSeadragon.Viewer#\n */\n canvas: null,\n\n // Overlays list. An overlay allows to add html on top of the viewer.\n overlays: [],\n // Container inside the canvas where overlays are drawn.\n overlaysContainer: null,\n\n //private state properties\n previousBody: [],\n\n //This was originally initialized in the constructor and so could never\n //have anything in it. now it can because we allow it to be specified\n //in the options and is only empty by default if not specified. Also\n //this array was returned from get_controls which I find confusing\n //since this object has a controls property which is treated in other\n //functions like clearControls. I'm removing the accessors.\n customControls: [],\n\n //These are originally not part options but declared as members\n //in initialize. It's still considered idiomatic to put them here\n source: null,\n /**\n * Handles rendering of tiles in the viewer. Created for each TileSource opened.\n * @member {OpenSeadragon.Drawer} drawer\n * @memberof OpenSeadragon.Viewer#\n */\n drawer: null,\n world: null,\n /**\n * Handles coordinate-related functionality - zoom, pan, rotation, etc. Created for each TileSource opened.\n * @member {OpenSeadragon.Viewport} viewport\n * @memberof OpenSeadragon.Viewer#\n */\n viewport: null,\n /**\n * @member {OpenSeadragon.Navigator} navigator\n * @memberof OpenSeadragon.Viewer#\n */\n navigator: null,\n\n //A collection viewport is a separate viewport used to provide\n //simultaneous rendering of sets of tiles\n collectionViewport: null,\n collectionDrawer: null,\n\n //UI image resources\n //TODO: rename navImages to uiImages\n navImages: null,\n\n //interface button controls\n buttons: null,\n\n //TODO: this is defunct so safely remove it\n profiler: null\n\n }, $.DEFAULT_SETTINGS, options );\n\n if ( typeof( this.hash) === \"undefined\" ) {\n throw new Error(\"A hash must be defined, either by specifying options.id or options.hash.\");\n }\n if ( typeof( THIS[ this.hash ] ) !== \"undefined\" ) {\n // We don't want to throw an error here, as the user might have discarded\n // the previous viewer with the same hash and now want to recreate it.\n $.console.warn(\"Hash \" + this.hash + \" has already been used.\");\n }\n\n //Private state properties\n THIS[ this.hash ] = {\n \"fsBoundsDelta\": new $.Point( 1, 1 ),\n \"prevContainerSize\": null,\n \"animating\": false,\n \"forceRedraw\": false,\n \"mouseInside\": false,\n \"group\": null,\n // whether we should be continuously zooming\n \"zooming\": false,\n // how much we should be continuously zooming by\n \"zoomFactor\": null,\n \"lastZoomTime\": null,\n \"fullPage\": false,\n \"onfullscreenchange\": null\n };\n\n this._sequenceIndex = 0;\n this._firstOpen = true;\n this._updateRequestId = null;\n this._loadQueue = [];\n this.currentOverlays = [];\n\n this._lastScrollTime = $.now(); // variable used to help normalize the scroll event speed of different devices\n\n //Inherit some behaviors and properties\n $.EventSource.call( this );\n\n this.addHandler( 'open-failed', function ( event ) {\n var msg = $.getString( \"Errors.OpenFailed\", event.eventSource, event.message);\n _this._showMessage( msg );\n });\n\n $.ControlDock.call( this, options );\n\n //Deal with tile sources\n if (this.xmlPath) {\n //Deprecated option. Now it is preferred to use the tileSources option\n this.tileSources = [ this.xmlPath ];\n }\n\n this.element = this.element || document.getElementById( this.id );\n this.canvas = $.makeNeutralElement( \"div\" );\n\n this.canvas.className = \"openseadragon-canvas\";\n (function( style ){\n style.width = \"100%\";\n style.height = \"100%\";\n style.overflow = \"hidden\";\n style.position = \"absolute\";\n style.top = \"0px\";\n style.left = \"0px\";\n }(this.canvas.style));\n $.setElementTouchActionNone( this.canvas );\n if (options.tabIndex !== \"\") {\n this.canvas.tabIndex = (options.tabIndex === undefined ? 0 : options.tabIndex);\n }\n\n //the container is created through applying the ControlDock constructor above\n this.container.className = \"openseadragon-container\";\n (function( style ){\n style.width = \"100%\";\n style.height = \"100%\";\n style.position = \"relative\";\n style.overflow = \"hidden\";\n style.left = \"0px\";\n style.top = \"0px\";\n style.textAlign = \"left\"; // needed to protect against\n }( this.container.style ));\n\n this.container.insertBefore( this.canvas, this.container.firstChild );\n this.element.appendChild( this.container );\n\n //Used for toggling between fullscreen and default container size\n //TODO: these can be closure private and shared across Viewer\n // instances.\n this.bodyWidth = document.body.style.width;\n this.bodyHeight = document.body.style.height;\n this.bodyOverflow = document.body.style.overflow;\n this.docOverflow = document.documentElement.style.overflow;\n\n this.innerTracker = new $.MouseTracker({\n element: this.canvas,\n startDisabled: !this.mouseNavEnabled,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n dblClickTimeThreshold: this.dblClickTimeThreshold,\n dblClickDistThreshold: this.dblClickDistThreshold,\n keyDownHandler: $.delegate( this, onCanvasKeyDown ),\n keyHandler: $.delegate( this, onCanvasKeyPress ),\n clickHandler: $.delegate( this, onCanvasClick ),\n dblClickHandler: $.delegate( this, onCanvasDblClick ),\n dragHandler: $.delegate( this, onCanvasDrag ),\n dragEndHandler: $.delegate( this, onCanvasDragEnd ),\n enterHandler: $.delegate( this, onCanvasEnter ),\n exitHandler: $.delegate( this, onCanvasExit ),\n pressHandler: $.delegate( this, onCanvasPress ),\n releaseHandler: $.delegate( this, onCanvasRelease ),\n nonPrimaryPressHandler: $.delegate( this, onCanvasNonPrimaryPress ),\n nonPrimaryReleaseHandler: $.delegate( this, onCanvasNonPrimaryRelease ),\n scrollHandler: $.delegate( this, onCanvasScroll ),\n pinchHandler: $.delegate( this, onCanvasPinch )\n });\n\n this.outerTracker = new $.MouseTracker({\n element: this.container,\n startDisabled: !this.mouseNavEnabled,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n dblClickTimeThreshold: this.dblClickTimeThreshold,\n dblClickDistThreshold: this.dblClickDistThreshold,\n enterHandler: $.delegate( this, onContainerEnter ),\n exitHandler: $.delegate( this, onContainerExit )\n });\n\n if( this.toolbar ){\n this.toolbar = new $.ControlDock({ element: this.toolbar });\n }\n\n this.bindStandardControls();\n\n THIS[ this.hash ].prevContainerSize = _getSafeElemSize( this.container );\n\n // Create the world\n this.world = new $.World({\n viewer: this\n });\n\n this.world.addHandler('add-item', function(event) {\n // For backwards compatibility, we maintain the source property\n _this.source = _this.world.getItemAt(0).source;\n\n THIS[ _this.hash ].forceRedraw = true;\n\n if (!_this._updateRequestId) {\n _this._updateRequestId = scheduleUpdate( _this, updateMulti );\n }\n });\n\n this.world.addHandler('remove-item', function(event) {\n // For backwards compatibility, we maintain the source property\n if (_this.world.getItemCount()) {\n _this.source = _this.world.getItemAt(0).source;\n } else {\n _this.source = null;\n }\n\n THIS[ _this.hash ].forceRedraw = true;\n });\n\n this.world.addHandler('metrics-change', function(event) {\n if (_this.viewport) {\n _this.viewport._setContentBounds(_this.world.getHomeBounds(), _this.world.getContentFactor());\n }\n });\n\n this.world.addHandler('item-index-change', function(event) {\n // For backwards compatibility, we maintain the source property\n _this.source = _this.world.getItemAt(0).source;\n });\n\n // Create the viewport\n this.viewport = new $.Viewport({\n containerSize: THIS[ this.hash ].prevContainerSize,\n springStiffness: this.springStiffness,\n animationTime: this.animationTime,\n minZoomImageRatio: this.minZoomImageRatio,\n maxZoomPixelRatio: this.maxZoomPixelRatio,\n visibilityRatio: this.visibilityRatio,\n wrapHorizontal: this.wrapHorizontal,\n wrapVertical: this.wrapVertical,\n defaultZoomLevel: this.defaultZoomLevel,\n minZoomLevel: this.minZoomLevel,\n maxZoomLevel: this.maxZoomLevel,\n viewer: this,\n degrees: this.degrees,\n navigatorRotate: this.navigatorRotate,\n homeFillsViewer: this.homeFillsViewer,\n margins: this.viewportMargins\n });\n\n this.viewport._setContentBounds(this.world.getHomeBounds(), this.world.getContentFactor());\n\n // Create the image loader\n this.imageLoader = new $.ImageLoader({\n jobLimit: this.imageLoaderLimit,\n timeout: options.timeout\n });\n\n // Create the tile cache\n this.tileCache = new $.TileCache({\n maxImageCacheCount: this.maxImageCacheCount\n });\n\n // Create the drawer\n this.drawer = new $.Drawer({\n viewer: this,\n viewport: this.viewport,\n element: this.canvas,\n debugGridColor: this.debugGridColor\n });\n\n // Overlay container\n this.overlaysContainer = $.makeNeutralElement( \"div\" );\n this.canvas.appendChild( this.overlaysContainer );\n\n // Now that we have a drawer, see if it supports rotate. If not we need to remove the rotate buttons\n if (!this.drawer.canRotate()) {\n // Disable/remove the rotate left/right buttons since they aren't supported\n if (this.rotateLeft) {\n i = this.buttons.buttons.indexOf(this.rotateLeft);\n this.buttons.buttons.splice(i, 1);\n this.buttons.element.removeChild(this.rotateLeft.element);\n }\n if (this.rotateRight) {\n i = this.buttons.buttons.indexOf(this.rotateRight);\n this.buttons.buttons.splice(i, 1);\n this.buttons.element.removeChild(this.rotateRight.element);\n }\n }\n\n //Instantiate a navigator if configured\n if ( this.showNavigator){\n this.navigator = new $.Navigator({\n id: this.navigatorId,\n position: this.navigatorPosition,\n sizeRatio: this.navigatorSizeRatio,\n maintainSizeRatio: this.navigatorMaintainSizeRatio,\n top: this.navigatorTop,\n left: this.navigatorLeft,\n width: this.navigatorWidth,\n height: this.navigatorHeight,\n autoResize: this.navigatorAutoResize,\n autoFade: this.navigatorAutoFade,\n prefixUrl: this.prefixUrl,\n viewer: this,\n navigatorRotate: this.navigatorRotate,\n crossOriginPolicy: this.crossOriginPolicy\n });\n }\n\n // Sequence mode\n if (this.sequenceMode) {\n this.bindSequenceControls();\n }\n\n // Open initial tilesources\n if (this.tileSources) {\n this.open( this.tileSources );\n }\n\n // Add custom controls\n for ( i = 0; i < this.customControls.length; i++ ) {\n this.addControl(\n this.customControls[ i ].id,\n {anchor: this.customControls[ i ].anchor}\n );\n }\n\n // Initial fade out\n $.requestAnimationFrame( function(){\n beginControlsAutoHide( _this );\n } );\n};\n\n$.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, /** @lends OpenSeadragon.Viewer.prototype */{\n\n\n /**\n * @function\n * @return {Boolean}\n */\n isOpen: function () {\n return !!this.world.getItemCount();\n },\n\n // deprecated\n openDzi: function ( dzi ) {\n $.console.error( \"[Viewer.openDzi] this function is deprecated; use Viewer.open() instead.\" );\n return this.open( dzi );\n },\n\n // deprecated\n openTileSource: function ( tileSource ) {\n $.console.error( \"[Viewer.openTileSource] this function is deprecated; use Viewer.open() instead.\" );\n return this.open( tileSource );\n },\n\n /**\n * Open tiled images into the viewer, closing any others.\n * @function\n * @param {Array|String|Object|Function} tileSources - This can be a TiledImage\n * specifier, a TileSource specifier, or an array of either. A TiledImage specifier\n * is the same as the options parameter for {@link OpenSeadragon.Viewer#addTiledImage},\n * except for the index property; images are added in sequence.\n * A TileSource specifier is anything you could pass as the tileSource property\n * of the options parameter for {@link OpenSeadragon.Viewer#addTiledImage}.\n * @param {Number} initialPage - If sequenceMode is true, display this page initially\n * for the given tileSources. If specified, will overwrite the Viewer's existing initialPage property.\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:open\n * @fires OpenSeadragon.Viewer.event:open-failed\n */\n open: function (tileSources, initialPage) {\n var _this = this;\n\n this.close();\n\n if (!tileSources) {\n return;\n }\n\n if (this.sequenceMode && $.isArray(tileSources)) {\n if (this.referenceStrip) {\n this.referenceStrip.destroy();\n this.referenceStrip = null;\n }\n\n if (typeof initialPage != 'undefined' && !isNaN(initialPage)) {\n this.initialPage = initialPage;\n }\n\n this.tileSources = tileSources;\n this._sequenceIndex = Math.max(0, Math.min(this.tileSources.length - 1, this.initialPage));\n if (this.tileSources.length) {\n this.open(this.tileSources[this._sequenceIndex]);\n\n if ( this.showReferenceStrip ){\n this.addReferenceStrip();\n }\n }\n\n this._updateSequenceButtons( this._sequenceIndex );\n return;\n }\n\n if (!$.isArray(tileSources)) {\n tileSources = [tileSources];\n }\n\n if (!tileSources.length) {\n return;\n }\n\n this._opening = true;\n\n var expected = tileSources.length;\n var successes = 0;\n var failures = 0;\n var failEvent;\n\n var checkCompletion = function() {\n if (successes + failures === expected) {\n if (successes) {\n if (_this._firstOpen || !_this.preserveViewport) {\n _this.viewport.goHome( true );\n _this.viewport.update();\n }\n\n _this._firstOpen = false;\n\n var source = tileSources[0];\n if (source.tileSource) {\n source = source.tileSource;\n }\n\n // Global overlays\n if( _this.overlays && !_this.preserveOverlays ){\n for ( var i = 0; i < _this.overlays.length; i++ ) {\n _this.currentOverlays[ i ] = getOverlayObject( _this, _this.overlays[ i ] );\n }\n }\n\n _this._drawOverlays();\n _this._opening = false;\n\n /**\n * Raised when the viewer has opened and loaded one or more TileSources.\n *\n * @event open\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {OpenSeadragon.TileSource} source - The tile source that was opened.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n // TODO: what if there are multiple sources?\n _this.raiseEvent( 'open', { source: source } );\n } else {\n _this._opening = false;\n\n /**\n * Raised when an error occurs loading a TileSource.\n *\n * @event open-failed\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {String} message - Information about what failed.\n * @property {String} source - The tile source that failed.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( 'open-failed', failEvent );\n }\n }\n };\n\n var doOne = function(options) {\n if (!$.isPlainObject(options) || !options.tileSource) {\n options = {\n tileSource: options\n };\n }\n\n if (options.index !== undefined) {\n $.console.error('[Viewer.open] setting indexes here is not supported; use addTiledImage instead');\n delete options.index;\n }\n\n if (options.collectionImmediately === undefined) {\n options.collectionImmediately = true;\n }\n\n var originalSuccess = options.success;\n options.success = function(event) {\n successes++;\n\n // TODO: now that options has other things besides tileSource, the overlays\n // should probably be at the options level, not the tileSource level.\n if (options.tileSource.overlays) {\n for (var i = 0; i < options.tileSource.overlays.length; i++) {\n _this.addOverlay(options.tileSource.overlays[i]);\n }\n }\n\n if (originalSuccess) {\n originalSuccess(event);\n }\n\n checkCompletion();\n };\n\n var originalError = options.error;\n options.error = function(event) {\n failures++;\n\n if (!failEvent) {\n failEvent = event;\n }\n\n if (originalError) {\n originalError(event);\n }\n\n checkCompletion();\n };\n\n _this.addTiledImage(options);\n };\n\n // TileSources\n for (var i = 0; i < tileSources.length; i++) {\n doOne(tileSources[i]);\n }\n\n return this;\n },\n\n\n /**\n * @function\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:close\n */\n close: function ( ) {\n if ( !THIS[ this.hash ] ) {\n //this viewer has already been destroyed: returning immediately\n return this;\n }\n\n this._opening = false;\n\n if ( this.navigator ) {\n this.navigator.close();\n }\n\n if (!this.preserveOverlays) {\n this.clearOverlays();\n this.overlaysContainer.innerHTML = \"\";\n }\n\n THIS[ this.hash ].animating = false;\n this.world.removeAll();\n this.imageLoader.clear();\n\n /**\n * Raised when the viewer is closed (see {@link OpenSeadragon.Viewer#close}).\n *\n * @event close\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'close' );\n\n return this;\n },\n\n\n /**\n * Function to destroy the viewer and clean up everything created by OpenSeadragon.\n *\n * Example:\n * var viewer = OpenSeadragon({\n * [...]\n * });\n *\n * //when you are done with the viewer:\n * viewer.destroy();\n * viewer = null; //important\n *\n * @function\n */\n destroy: function( ) {\n if ( !THIS[ this.hash ] ) {\n //this viewer has already been destroyed: returning immediately\n return;\n }\n\n this.close();\n\n this.clearOverlays();\n this.overlaysContainer.innerHTML = \"\";\n\n //TODO: implement this...\n //this.unbindSequenceControls()\n //this.unbindStandardControls()\n\n if (this.referenceStrip) {\n this.referenceStrip.destroy();\n this.referenceStrip = null;\n }\n\n if ( this._updateRequestId !== null ) {\n $.cancelAnimationFrame( this._updateRequestId );\n this._updateRequestId = null;\n }\n\n if ( this.drawer ) {\n this.drawer.destroy();\n }\n\n this.removeAllHandlers();\n\n // Go through top element (passed to us) and remove all children\n // Use removeChild to make sure it handles SVG or any non-html\n // also it performs better - http://jsperf.com/innerhtml-vs-removechild/15\n if (this.element){\n while (this.element.firstChild) {\n this.element.removeChild(this.element.firstChild);\n }\n }\n\n // destroy the mouse trackers\n if (this.innerTracker){\n this.innerTracker.destroy();\n }\n if (this.outerTracker){\n this.outerTracker.destroy();\n }\n\n THIS[ this.hash ] = null;\n delete THIS[ this.hash ];\n\n // clear all our references to dom objects\n this.canvas = null;\n this.container = null;\n\n // clear our reference to the main element - they will need to pass it in again, creating a new viewer\n this.element = null;\n },\n\n /**\n * @function\n * @return {Boolean}\n */\n isMouseNavEnabled: function () {\n return this.innerTracker.isTracking();\n },\n\n /**\n * @function\n * @param {Boolean} enabled - true to enable, false to disable\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:mouse-enabled\n */\n setMouseNavEnabled: function( enabled ){\n this.innerTracker.setTracking( enabled );\n this.outerTracker.setTracking( enabled );\n /**\n * Raised when mouse/touch navigation is enabled or disabled (see {@link OpenSeadragon.Viewer#setMouseNavEnabled}).\n *\n * @event mouse-enabled\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Boolean} enabled\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'mouse-enabled', { enabled: enabled } );\n return this;\n },\n\n\n /**\n * @function\n * @return {Boolean}\n */\n areControlsEnabled: function () {\n var enabled = this.controls.length,\n i;\n for( i = 0; i < this.controls.length; i++ ){\n enabled = enabled && this.controls[ i ].isVisibile();\n }\n return enabled;\n },\n\n\n /**\n * Shows or hides the controls (e.g. the default navigation buttons).\n *\n * @function\n * @param {Boolean} true to show, false to hide.\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:controls-enabled\n */\n setControlsEnabled: function( enabled ) {\n if( enabled ){\n abortControlsAutoHide( this );\n } else {\n beginControlsAutoHide( this );\n }\n /**\n * Raised when the navigation controls are shown or hidden (see {@link OpenSeadragon.Viewer#setControlsEnabled}).\n *\n * @event controls-enabled\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Boolean} enabled\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'controls-enabled', { enabled: enabled } );\n return this;\n },\n\n /**\n * Turns debugging mode on or off for this viewer.\n *\n * @function\n * @param {Boolean} true to turn debug on, false to turn debug off.\n */\n setDebugMode: function(debugMode){\n\n for (var i = 0; i < this.world.getItemCount(); i++) {\n this.world.getItemAt(i).debugMode = debugMode;\n }\n\n this.debugMode = debugMode;\n this.forceRedraw();\n },\n\n /**\n * @function\n * @return {Boolean}\n */\n isFullPage: function () {\n return THIS[ this.hash ].fullPage;\n },\n\n\n /**\n * Toggle full page mode.\n * @function\n * @param {Boolean} fullPage\n * If true, enter full page mode. If false, exit full page mode.\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:pre-full-page\n * @fires OpenSeadragon.Viewer.event:full-page\n */\n setFullPage: function( fullPage ) {\n\n var body = document.body,\n bodyStyle = body.style,\n docStyle = document.documentElement.style,\n _this = this,\n nodes,\n i;\n\n //dont bother modifying the DOM if we are already in full page mode.\n if ( fullPage == this.isFullPage() ) {\n return this;\n }\n\n var fullPageEventArgs = {\n fullPage: fullPage,\n preventDefaultAction: false\n };\n /**\n * Raised when the viewer is about to change to/from full-page mode (see {@link OpenSeadragon.Viewer#setFullPage}).\n *\n * @event pre-full-page\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Boolean} fullPage - True if entering full-page mode, false if exiting full-page mode.\n * @property {Boolean} preventDefaultAction - Set to true to prevent full-page mode change. Default: false.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'pre-full-page', fullPageEventArgs );\n if ( fullPageEventArgs.preventDefaultAction ) {\n return this;\n }\n\n if ( fullPage ) {\n\n this.elementSize = $.getElementSize( this.element );\n this.pageScroll = $.getPageScroll();\n\n this.elementMargin = this.element.style.margin;\n this.element.style.margin = \"0\";\n this.elementPadding = this.element.style.padding;\n this.element.style.padding = \"0\";\n\n this.bodyMargin = bodyStyle.margin;\n this.docMargin = docStyle.margin;\n bodyStyle.margin = \"0\";\n docStyle.margin = \"0\";\n\n this.bodyPadding = bodyStyle.padding;\n this.docPadding = docStyle.padding;\n bodyStyle.padding = \"0\";\n docStyle.padding = \"0\";\n\n this.bodyWidth = bodyStyle.width;\n this.docWidth = docStyle.width;\n bodyStyle.width = \"100%\";\n docStyle.width = \"100%\";\n\n this.bodyHeight = bodyStyle.height;\n this.docHeight = docStyle.height;\n bodyStyle.height = \"100%\";\n docStyle.height = \"100%\";\n\n //when entering full screen on the ipad it wasnt sufficient to leave\n //the body intact as only only the top half of the screen would\n //respond to touch events on the canvas, while the bottom half treated\n //them as touch events on the document body. Thus we remove and store\n //the bodies elements and replace them when we leave full screen.\n this.previousBody = [];\n THIS[ this.hash ].prevElementParent = this.element.parentNode;\n THIS[ this.hash ].prevNextSibling = this.element.nextSibling;\n THIS[ this.hash ].prevElementWidth = this.element.style.width;\n THIS[ this.hash ].prevElementHeight = this.element.style.height;\n nodes = body.childNodes.length;\n for ( i = 0; i < nodes; i++ ) {\n this.previousBody.push( body.childNodes[ 0 ] );\n body.removeChild( body.childNodes[ 0 ] );\n }\n\n //If we've got a toolbar, we need to enable the user to use css to\n //preserve it in fullpage mode\n if ( this.toolbar && this.toolbar.element ) {\n //save a reference to the parent so we can put it back\n //in the long run we need a better strategy\n this.toolbar.parentNode = this.toolbar.element.parentNode;\n this.toolbar.nextSibling = this.toolbar.element.nextSibling;\n body.appendChild( this.toolbar.element );\n\n //Make sure the user has some ability to style the toolbar based\n //on the mode\n $.addClass( this.toolbar.element, 'fullpage' );\n }\n\n $.addClass( this.element, 'fullpage' );\n body.appendChild( this.element );\n\n this.element.style.height = $.getWindowSize().y + 'px';\n this.element.style.width = $.getWindowSize().x + 'px';\n\n if ( this.toolbar && this.toolbar.element ) {\n this.element.style.height = (\n $.getElementSize( this.element ).y - $.getElementSize( this.toolbar.element ).y\n ) + 'px';\n }\n\n THIS[ this.hash ].fullPage = true;\n\n // mouse will be inside container now\n $.delegate( this, onContainerEnter )( {} );\n\n } else {\n\n this.element.style.margin = this.elementMargin;\n this.element.style.padding = this.elementPadding;\n\n bodyStyle.margin = this.bodyMargin;\n docStyle.margin = this.docMargin;\n\n bodyStyle.padding = this.bodyPadding;\n docStyle.padding = this.docPadding;\n\n bodyStyle.width = this.bodyWidth;\n docStyle.width = this.docWidth;\n\n bodyStyle.height = this.bodyHeight;\n docStyle.height = this.docHeight;\n\n body.removeChild( this.element );\n nodes = this.previousBody.length;\n for ( i = 0; i < nodes; i++ ) {\n body.appendChild( this.previousBody.shift() );\n }\n\n $.removeClass( this.element, 'fullpage' );\n THIS[ this.hash ].prevElementParent.insertBefore(\n this.element,\n THIS[ this.hash ].prevNextSibling\n );\n\n //If we've got a toolbar, we need to enable the user to use css to\n //reset it to its original state\n if ( this.toolbar && this.toolbar.element ) {\n body.removeChild( this.toolbar.element );\n\n //Make sure the user has some ability to style the toolbar based\n //on the mode\n $.removeClass( this.toolbar.element, 'fullpage' );\n\n this.toolbar.parentNode.insertBefore(\n this.toolbar.element,\n this.toolbar.nextSibling\n );\n delete this.toolbar.parentNode;\n delete this.toolbar.nextSibling;\n }\n\n this.element.style.width = THIS[ this.hash ].prevElementWidth;\n this.element.style.height = THIS[ this.hash ].prevElementHeight;\n\n // After exiting fullPage or fullScreen, it can take some time\n // before the browser can actually set the scroll.\n var restoreScrollCounter = 0;\n var restoreScroll = function() {\n $.setPageScroll( _this.pageScroll );\n var pageScroll = $.getPageScroll();\n restoreScrollCounter++;\n if (restoreScrollCounter < 10 &&\n (pageScroll.x !== _this.pageScroll.x ||\n pageScroll.y !== _this.pageScroll.y)) {\n $.requestAnimationFrame( restoreScroll );\n }\n };\n $.requestAnimationFrame( restoreScroll );\n\n THIS[ this.hash ].fullPage = false;\n\n // mouse will likely be outside now\n $.delegate( this, onContainerExit )( { } );\n\n }\n\n if ( this.navigator && this.viewport ) {\n this.navigator.update( this.viewport );\n }\n\n /**\n * Raised when the viewer has changed to/from full-page mode (see {@link OpenSeadragon.Viewer#setFullPage}).\n *\n * @event full-page\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Boolean} fullPage - True if changed to full-page mode, false if exited full-page mode.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'full-page', { fullPage: fullPage } );\n\n return this;\n },\n\n /**\n * Toggle full screen mode if supported. Toggle full page mode otherwise.\n * @function\n * @param {Boolean} fullScreen\n * If true, enter full screen mode. If false, exit full screen mode.\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:pre-full-screen\n * @fires OpenSeadragon.Viewer.event:full-screen\n */\n setFullScreen: function( fullScreen ) {\n var _this = this;\n\n if ( !$.supportsFullScreen ) {\n return this.setFullPage( fullScreen );\n }\n\n if ( $.isFullScreen() === fullScreen ) {\n return this;\n }\n\n var fullScreeEventArgs = {\n fullScreen: fullScreen,\n preventDefaultAction: false\n };\n /**\n * Raised when the viewer is about to change to/from full-screen mode (see {@link OpenSeadragon.Viewer#setFullScreen}).\n * Note: the pre-full-screen event is not raised when the user is exiting\n * full-screen mode by pressing the Esc key. In that case, consider using\n * the full-screen, pre-full-page or full-page events.\n *\n * @event pre-full-screen\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Boolean} fullScreen - True if entering full-screen mode, false if exiting full-screen mode.\n * @property {Boolean} preventDefaultAction - Set to true to prevent full-screen mode change. Default: false.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'pre-full-screen', fullScreeEventArgs );\n if ( fullScreeEventArgs.preventDefaultAction ) {\n return this;\n }\n\n if ( fullScreen ) {\n\n this.setFullPage( true );\n // If the full page mode is not actually entered, we need to prevent\n // the full screen mode.\n if ( !this.isFullPage() ) {\n return this;\n }\n\n this.fullPageStyleWidth = this.element.style.width;\n this.fullPageStyleHeight = this.element.style.height;\n this.element.style.width = '100%';\n this.element.style.height = '100%';\n\n var onFullScreenChange = function() {\n var isFullScreen = $.isFullScreen();\n if ( !isFullScreen ) {\n $.removeEvent( document, $.fullScreenEventName, onFullScreenChange );\n $.removeEvent( document, $.fullScreenErrorEventName, onFullScreenChange );\n\n _this.setFullPage( false );\n if ( _this.isFullPage() ) {\n _this.element.style.width = _this.fullPageStyleWidth;\n _this.element.style.height = _this.fullPageStyleHeight;\n }\n }\n if ( _this.navigator && _this.viewport ) {\n _this.navigator.update( _this.viewport );\n }\n /**\n * Raised when the viewer has changed to/from full-screen mode (see {@link OpenSeadragon.Viewer#setFullScreen}).\n *\n * @event full-screen\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Boolean} fullScreen - True if changed to full-screen mode, false if exited full-screen mode.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( 'full-screen', { fullScreen: isFullScreen } );\n };\n $.addEvent( document, $.fullScreenEventName, onFullScreenChange );\n $.addEvent( document, $.fullScreenErrorEventName, onFullScreenChange );\n\n $.requestFullScreen( document.body );\n\n } else {\n $.exitFullScreen();\n }\n return this;\n },\n\n /**\n * @function\n * @return {Boolean}\n */\n isVisible: function () {\n return this.container.style.visibility != \"hidden\";\n },\n\n\n /**\n * @function\n * @param {Boolean} visible\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:visible\n */\n setVisible: function( visible ){\n this.container.style.visibility = visible ? \"\" : \"hidden\";\n /**\n * Raised when the viewer is shown or hidden (see {@link OpenSeadragon.Viewer#setVisible}).\n *\n * @event visible\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Boolean} visible\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'visible', { visible: visible } );\n return this;\n },\n\n /**\n * Add a tiled image to the viewer.\n * options.tileSource can be anything that {@link OpenSeadragon.Viewer#open}\n * supports except arrays of images.\n * Note that you can specify options.width or options.height, but not both.\n * The other dimension will be calculated according to the item's aspect ratio.\n * If collectionMode is on (see {@link OpenSeadragon.Options}), the new image is\n * automatically arranged with the others.\n * @function\n * @param {Object} options\n * @param {String|Object|Function} options.tileSource - The TileSource specifier.\n * A String implies a url used to determine the tileSource implementation\n * based on the file extension of url. JSONP is implied by *.js,\n * otherwise the url is retrieved as text and the resulting text is\n * introspected to determine if its json, xml, or text and parsed.\n * An Object implies an inline configuration which has a single\n * property sufficient for being able to determine tileSource\n * implementation. If the object has a property which is a function\n * named 'getTileUrl', it is treated as a custom TileSource.\n * @param {Number} [options.index] The index of the item. Added on top of\n * all other items if not specified.\n * @param {Boolean} [options.replace=false] If true, the item at options.index will be\n * removed and the new item is added in its place. options.tileSource will be\n * interpreted and fetched if necessary before the old item is removed to avoid leaving\n * a gap in the world.\n * @param {Number} [options.x=0] The X position for the image in viewport coordinates.\n * @param {Number} [options.y=0] The Y position for the image in viewport coordinates.\n * @param {Number} [options.width=1] The width for the image in viewport coordinates.\n * @param {Number} [options.height] The height for the image in viewport coordinates.\n * @param {OpenSeadragon.Rect} [options.fitBounds] The bounds in viewport coordinates\n * to fit the image into. If specified, x, y, width and height get ignored.\n * @param {OpenSeadragon.Placement} [options.fitBoundsPlacement=OpenSeadragon.Placement.CENTER]\n * How to anchor the image in the bounds if options.fitBounds is set.\n * @param {OpenSeadragon.Rect} [options.clip] - An area, in image pixels, to clip to\n * (portions of the image outside of this area will not be visible). Only works on\n * browsers that support the HTML5 canvas.\n * @param {Number} [options.opacity=1] Proportional opacity of the tiled images (1=opaque, 0=hidden)\n * @param {Boolean} [options.preload=false] Default switch for loading hidden images (true loads, false blocks)\n * @param {Number} [options.degrees=0] Initial rotation of the tiled image around\n * its top left corner in degrees.\n * @param {String} [options.compositeOperation] How the image is composited onto other images.\n * @param {String} [options.crossOriginPolicy] The crossOriginPolicy for this specific image,\n * overriding viewer.crossOriginPolicy.\n * @param {Boolean} [options.ajaxWithCredentials] Whether to set withCredentials on tile AJAX\n * @param {Boolean} [options.loadTilesWithAjax]\n * Whether to load tile data using AJAX requests.\n * Defaults to the setting in {@link OpenSeadragon.Options}.\n * @param {Object} [options.ajaxHeaders]\n * A set of headers to include when making tile AJAX requests.\n * Note that these headers will be merged over any headers specified in {@link OpenSeadragon.Options}.\n * Specifying a falsy value for a header will clear its existing value set at the Viewer level (if any).\n * requests.\n * @param {Function} [options.success] A function that gets called when the image is\n * successfully added. It's passed the event object which contains a single property:\n * \"item\", the resulting TiledImage.\n * @param {Function} [options.error] A function that gets called if the image is\n * unable to be added. It's passed the error event object, which contains \"message\"\n * and \"source\" properties.\n * @param {Boolean} [options.collectionImmediately=false] If collectionMode is on,\n * specifies whether to snap to the new arrangement immediately or to animate to it.\n * @param {String|CanvasGradient|CanvasPattern|Function} [options.placeholderFillStyle] - See {@link OpenSeadragon.Options}.\n * @fires OpenSeadragon.World.event:add-item\n * @fires OpenSeadragon.Viewer.event:add-item-failed\n */\n addTiledImage: function( options ) {\n $.console.assert(options, \"[Viewer.addTiledImage] options is required\");\n $.console.assert(options.tileSource, \"[Viewer.addTiledImage] options.tileSource is required\");\n $.console.assert(!options.replace || (options.index > -1 && options.index < this.world.getItemCount()),\n \"[Viewer.addTiledImage] if options.replace is used, options.index must be a valid index in Viewer.world\");\n\n var _this = this;\n\n if (options.replace) {\n options.replaceItem = _this.world.getItemAt(options.index);\n }\n\n this._hideMessage();\n\n if (options.placeholderFillStyle === undefined) {\n options.placeholderFillStyle = this.placeholderFillStyle;\n }\n if (options.opacity === undefined) {\n options.opacity = this.opacity;\n }\n if (options.preload === undefined) {\n options.preload = this.preload;\n }\n if (options.compositeOperation === undefined) {\n options.compositeOperation = this.compositeOperation;\n }\n if (options.crossOriginPolicy === undefined) {\n options.crossOriginPolicy = options.tileSource.crossOriginPolicy !== undefined ? options.tileSource.crossOriginPolicy : this.crossOriginPolicy;\n }\n if (options.ajaxWithCredentials === undefined) {\n options.ajaxWithCredentials = this.ajaxWithCredentials;\n }\n if (options.loadTilesWithAjax === undefined) {\n options.loadTilesWithAjax = this.loadTilesWithAjax;\n }\n if (options.ajaxHeaders === undefined || options.ajaxHeaders === null) {\n options.ajaxHeaders = this.ajaxHeaders;\n } else if ($.isPlainObject(options.ajaxHeaders) && $.isPlainObject(this.ajaxHeaders)) {\n options.ajaxHeaders = $.extend({}, this.ajaxHeaders, options.ajaxHeaders);\n }\n\n var myQueueItem = {\n options: options\n };\n\n function raiseAddItemFailed( event ) {\n for (var i = 0; i < _this._loadQueue.length; i++) {\n if (_this._loadQueue[i] === myQueueItem) {\n _this._loadQueue.splice(i, 1);\n break;\n }\n }\n\n if (_this._loadQueue.length === 0) {\n refreshWorld(myQueueItem);\n }\n\n /**\n * Raised when an error occurs while adding a item.\n * @event add-item-failed\n * @memberOf OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {String} message\n * @property {String} source\n * @property {Object} options The options passed to the addTiledImage method.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( 'add-item-failed', event );\n\n if (options.error) {\n options.error(event);\n }\n }\n\n function refreshWorld(theItem) {\n if (_this.collectionMode) {\n _this.world.arrange({\n immediately: theItem.options.collectionImmediately,\n rows: _this.collectionRows,\n columns: _this.collectionColumns,\n layout: _this.collectionLayout,\n tileSize: _this.collectionTileSize,\n tileMargin: _this.collectionTileMargin\n });\n _this.world.setAutoRefigureSizes(true);\n }\n }\n\n if ($.isArray(options.tileSource)) {\n setTimeout(function() {\n raiseAddItemFailed({\n message: \"[Viewer.addTiledImage] Sequences can not be added; add them one at a time instead.\",\n source: options.tileSource,\n options: options\n });\n });\n return;\n }\n\n this._loadQueue.push(myQueueItem);\n\n function processReadyItems() {\n var queueItem, tiledImage, optionsClone;\n while (_this._loadQueue.length) {\n queueItem = _this._loadQueue[0];\n if (!queueItem.tileSource) {\n break;\n }\n\n _this._loadQueue.splice(0, 1);\n\n if (queueItem.options.replace) {\n var newIndex = _this.world.getIndexOfItem(queueItem.options.replaceItem);\n if (newIndex != -1) {\n queueItem.options.index = newIndex;\n }\n _this.world.removeItem(queueItem.options.replaceItem);\n }\n\n tiledImage = new $.TiledImage({\n viewer: _this,\n source: queueItem.tileSource,\n viewport: _this.viewport,\n drawer: _this.drawer,\n tileCache: _this.tileCache,\n imageLoader: _this.imageLoader,\n x: queueItem.options.x,\n y: queueItem.options.y,\n width: queueItem.options.width,\n height: queueItem.options.height,\n fitBounds: queueItem.options.fitBounds,\n fitBoundsPlacement: queueItem.options.fitBoundsPlacement,\n clip: queueItem.options.clip,\n placeholderFillStyle: queueItem.options.placeholderFillStyle,\n opacity: queueItem.options.opacity,\n preload: queueItem.options.preload,\n degrees: queueItem.options.degrees,\n compositeOperation: queueItem.options.compositeOperation,\n springStiffness: _this.springStiffness,\n animationTime: _this.animationTime,\n minZoomImageRatio: _this.minZoomImageRatio,\n wrapHorizontal: _this.wrapHorizontal,\n wrapVertical: _this.wrapVertical,\n immediateRender: _this.immediateRender,\n blendTime: _this.blendTime,\n alwaysBlend: _this.alwaysBlend,\n minPixelRatio: _this.minPixelRatio,\n smoothTileEdgesMinZoom: _this.smoothTileEdgesMinZoom,\n iOSDevice: _this.iOSDevice,\n crossOriginPolicy: queueItem.options.crossOriginPolicy,\n ajaxWithCredentials: queueItem.options.ajaxWithCredentials,\n loadTilesWithAjax: queueItem.options.loadTilesWithAjax,\n ajaxHeaders: queueItem.options.ajaxHeaders,\n debugMode: _this.debugMode\n });\n\n if (_this.collectionMode) {\n _this.world.setAutoRefigureSizes(false);\n }\n _this.world.addItem( tiledImage, {\n index: queueItem.options.index\n });\n\n if (_this._loadQueue.length === 0) {\n //this restores the autoRefigureSizes flag to true.\n refreshWorld(queueItem);\n }\n\n if (_this.world.getItemCount() === 1 && !_this.preserveViewport) {\n _this.viewport.goHome(true);\n }\n\n if (_this.navigator) {\n optionsClone = $.extend({}, queueItem.options, {\n replace: false, // navigator already removed the layer, nothing to replace\n originalTiledImage: tiledImage,\n tileSource: queueItem.tileSource\n });\n\n _this.navigator.addTiledImage(optionsClone);\n }\n\n if (queueItem.options.success) {\n queueItem.options.success({\n item: tiledImage\n });\n }\n }\n }\n\n getTileSourceImplementation( this, options.tileSource, options, function( tileSource ) {\n\n myQueueItem.tileSource = tileSource;\n\n // add everybody at the front of the queue that's ready to go\n processReadyItems();\n }, function( event ) {\n event.options = options;\n raiseAddItemFailed(event);\n\n // add everybody at the front of the queue that's ready to go\n processReadyItems();\n } );\n },\n\n /**\n * Add a simple image to the viewer.\n * The options are the same as the ones in {@link OpenSeadragon.Viewer#addTiledImage}\n * except for options.tileSource which is replaced by options.url.\n * @function\n * @param {Object} options - See {@link OpenSeadragon.Viewer#addTiledImage}\n * for all the options\n * @param {String} options.url - The URL of the image to add.\n * @fires OpenSeadragon.World.event:add-item\n * @fires OpenSeadragon.Viewer.event:add-item-failed\n */\n addSimpleImage: function(options) {\n $.console.assert(options, \"[Viewer.addSimpleImage] options is required\");\n $.console.assert(options.url, \"[Viewer.addSimpleImage] options.url is required\");\n\n var opts = $.extend({}, options, {\n tileSource: {\n type: 'image',\n url: options.url\n }\n });\n delete opts.url;\n this.addTiledImage(opts);\n },\n\n // deprecated\n addLayer: function( options ) {\n var _this = this;\n\n $.console.error( \"[Viewer.addLayer] this function is deprecated; use Viewer.addTiledImage() instead.\" );\n\n var optionsClone = $.extend({}, options, {\n success: function(event) {\n _this.raiseEvent(\"add-layer\", {\n options: options,\n drawer: event.item\n });\n },\n error: function(event) {\n _this.raiseEvent(\"add-layer-failed\", event);\n }\n });\n\n this.addTiledImage(optionsClone);\n return this;\n },\n\n // deprecated\n getLayerAtLevel: function( level ) {\n $.console.error( \"[Viewer.getLayerAtLevel] this function is deprecated; use World.getItemAt() instead.\" );\n return this.world.getItemAt(level);\n },\n\n // deprecated\n getLevelOfLayer: function( drawer ) {\n $.console.error( \"[Viewer.getLevelOfLayer] this function is deprecated; use World.getIndexOfItem() instead.\" );\n return this.world.getIndexOfItem(drawer);\n },\n\n // deprecated\n getLayersCount: function() {\n $.console.error( \"[Viewer.getLayersCount] this function is deprecated; use World.getItemCount() instead.\" );\n return this.world.getItemCount();\n },\n\n // deprecated\n setLayerLevel: function( drawer, level ) {\n $.console.error( \"[Viewer.setLayerLevel] this function is deprecated; use World.setItemIndex() instead.\" );\n return this.world.setItemIndex(drawer, level);\n },\n\n // deprecated\n removeLayer: function( drawer ) {\n $.console.error( \"[Viewer.removeLayer] this function is deprecated; use World.removeItem() instead.\" );\n return this.world.removeItem(drawer);\n },\n\n /**\n * Force the viewer to redraw its contents.\n * @returns {OpenSeadragon.Viewer} Chainable.\n */\n forceRedraw: function() {\n THIS[ this.hash ].forceRedraw = true;\n return this;\n },\n\n /**\n * @function\n * @return {OpenSeadragon.Viewer} Chainable.\n */\n bindSequenceControls: function(){\n\n //////////////////////////////////////////////////////////////////////////\n // Image Sequence Controls\n //////////////////////////////////////////////////////////////////////////\n var onFocusHandler = $.delegate( this, onFocus ),\n onBlurHandler = $.delegate( this, onBlur ),\n onNextHandler = $.delegate( this, onNext ),\n onPreviousHandler = $.delegate( this, onPrevious ),\n navImages = this.navImages,\n useGroup = true;\n\n if( this.showSequenceControl ){\n\n if( this.previousButton || this.nextButton ){\n //if we are binding to custom buttons then layout and\n //grouping is the responsibility of the page author\n useGroup = false;\n }\n\n this.previousButton = new $.Button({\n element: this.previousButton ? $.getElement( this.previousButton ) : null,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n tooltip: $.getString( \"Tooltips.PreviousPage\" ),\n srcRest: resolveUrl( this.prefixUrl, navImages.previous.REST ),\n srcGroup: resolveUrl( this.prefixUrl, navImages.previous.GROUP ),\n srcHover: resolveUrl( this.prefixUrl, navImages.previous.HOVER ),\n srcDown: resolveUrl( this.prefixUrl, navImages.previous.DOWN ),\n onRelease: onPreviousHandler,\n onFocus: onFocusHandler,\n onBlur: onBlurHandler\n });\n\n this.nextButton = new $.Button({\n element: this.nextButton ? $.getElement( this.nextButton ) : null,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n tooltip: $.getString( \"Tooltips.NextPage\" ),\n srcRest: resolveUrl( this.prefixUrl, navImages.next.REST ),\n srcGroup: resolveUrl( this.prefixUrl, navImages.next.GROUP ),\n srcHover: resolveUrl( this.prefixUrl, navImages.next.HOVER ),\n srcDown: resolveUrl( this.prefixUrl, navImages.next.DOWN ),\n onRelease: onNextHandler,\n onFocus: onFocusHandler,\n onBlur: onBlurHandler\n });\n\n if( !this.navPrevNextWrap ){\n this.previousButton.disable();\n }\n\n if (!this.tileSources || !this.tileSources.length) {\n this.nextButton.disable();\n }\n\n if( useGroup ){\n this.paging = new $.ButtonGroup({\n buttons: [\n this.previousButton,\n this.nextButton\n ],\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold\n });\n\n this.pagingControl = this.paging.element;\n\n if( this.toolbar ){\n this.toolbar.addControl(\n this.pagingControl,\n {anchor: $.ControlAnchor.BOTTOM_RIGHT}\n );\n }else{\n this.addControl(\n this.pagingControl,\n {anchor: this.sequenceControlAnchor || $.ControlAnchor.TOP_LEFT}\n );\n }\n }\n }\n return this;\n },\n\n\n /**\n * @function\n * @return {OpenSeadragon.Viewer} Chainable.\n */\n bindStandardControls: function(){\n //////////////////////////////////////////////////////////////////////////\n // Navigation Controls\n //////////////////////////////////////////////////////////////////////////\n var beginZoomingInHandler = $.delegate( this, beginZoomingIn ),\n endZoomingHandler = $.delegate( this, endZooming ),\n doSingleZoomInHandler = $.delegate( this, doSingleZoomIn ),\n beginZoomingOutHandler = $.delegate( this, beginZoomingOut ),\n doSingleZoomOutHandler = $.delegate( this, doSingleZoomOut ),\n onHomeHandler = $.delegate( this, onHome ),\n onFullScreenHandler = $.delegate( this, onFullScreen ),\n onRotateLeftHandler = $.delegate( this, onRotateLeft ),\n onRotateRightHandler = $.delegate( this, onRotateRight ),\n onFocusHandler = $.delegate( this, onFocus ),\n onBlurHandler = $.delegate( this, onBlur ),\n navImages = this.navImages,\n buttons = [],\n useGroup = true;\n\n\n if ( this.showNavigationControl ) {\n\n if( this.zoomInButton || this.zoomOutButton ||\n this.homeButton || this.fullPageButton ||\n this.rotateLeftButton || this.rotateRightButton ) {\n //if we are binding to custom buttons then layout and\n //grouping is the responsibility of the page author\n useGroup = false;\n }\n\n if ( this.showZoomControl ) {\n buttons.push( this.zoomInButton = new $.Button({\n element: this.zoomInButton ? $.getElement( this.zoomInButton ) : null,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n tooltip: $.getString( \"Tooltips.ZoomIn\" ),\n srcRest: resolveUrl( this.prefixUrl, navImages.zoomIn.REST ),\n srcGroup: resolveUrl( this.prefixUrl, navImages.zoomIn.GROUP ),\n srcHover: resolveUrl( this.prefixUrl, navImages.zoomIn.HOVER ),\n srcDown: resolveUrl( this.prefixUrl, navImages.zoomIn.DOWN ),\n onPress: beginZoomingInHandler,\n onRelease: endZoomingHandler,\n onClick: doSingleZoomInHandler,\n onEnter: beginZoomingInHandler,\n onExit: endZoomingHandler,\n onFocus: onFocusHandler,\n onBlur: onBlurHandler\n }));\n\n buttons.push( this.zoomOutButton = new $.Button({\n element: this.zoomOutButton ? $.getElement( this.zoomOutButton ) : null,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n tooltip: $.getString( \"Tooltips.ZoomOut\" ),\n srcRest: resolveUrl( this.prefixUrl, navImages.zoomOut.REST ),\n srcGroup: resolveUrl( this.prefixUrl, navImages.zoomOut.GROUP ),\n srcHover: resolveUrl( this.prefixUrl, navImages.zoomOut.HOVER ),\n srcDown: resolveUrl( this.prefixUrl, navImages.zoomOut.DOWN ),\n onPress: beginZoomingOutHandler,\n onRelease: endZoomingHandler,\n onClick: doSingleZoomOutHandler,\n onEnter: beginZoomingOutHandler,\n onExit: endZoomingHandler,\n onFocus: onFocusHandler,\n onBlur: onBlurHandler\n }));\n }\n\n if ( this.showHomeControl ) {\n buttons.push( this.homeButton = new $.Button({\n element: this.homeButton ? $.getElement( this.homeButton ) : null,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n tooltip: $.getString( \"Tooltips.Home\" ),\n srcRest: resolveUrl( this.prefixUrl, navImages.home.REST ),\n srcGroup: resolveUrl( this.prefixUrl, navImages.home.GROUP ),\n srcHover: resolveUrl( this.prefixUrl, navImages.home.HOVER ),\n srcDown: resolveUrl( this.prefixUrl, navImages.home.DOWN ),\n onRelease: onHomeHandler,\n onFocus: onFocusHandler,\n onBlur: onBlurHandler\n }));\n }\n\n if ( this.showFullPageControl ) {\n buttons.push( this.fullPageButton = new $.Button({\n element: this.fullPageButton ? $.getElement( this.fullPageButton ) : null,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n tooltip: $.getString( \"Tooltips.FullPage\" ),\n srcRest: resolveUrl( this.prefixUrl, navImages.fullpage.REST ),\n srcGroup: resolveUrl( this.prefixUrl, navImages.fullpage.GROUP ),\n srcHover: resolveUrl( this.prefixUrl, navImages.fullpage.HOVER ),\n srcDown: resolveUrl( this.prefixUrl, navImages.fullpage.DOWN ),\n onRelease: onFullScreenHandler,\n onFocus: onFocusHandler,\n onBlur: onBlurHandler\n }));\n }\n\n if ( this.showRotationControl ) {\n buttons.push( this.rotateLeftButton = new $.Button({\n element: this.rotateLeftButton ? $.getElement( this.rotateLeftButton ) : null,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n tooltip: $.getString( \"Tooltips.RotateLeft\" ),\n srcRest: resolveUrl( this.prefixUrl, navImages.rotateleft.REST ),\n srcGroup: resolveUrl( this.prefixUrl, navImages.rotateleft.GROUP ),\n srcHover: resolveUrl( this.prefixUrl, navImages.rotateleft.HOVER ),\n srcDown: resolveUrl( this.prefixUrl, navImages.rotateleft.DOWN ),\n onRelease: onRotateLeftHandler,\n onFocus: onFocusHandler,\n onBlur: onBlurHandler\n }));\n\n buttons.push( this.rotateRightButton = new $.Button({\n element: this.rotateRightButton ? $.getElement( this.rotateRightButton ) : null,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n tooltip: $.getString( \"Tooltips.RotateRight\" ),\n srcRest: resolveUrl( this.prefixUrl, navImages.rotateright.REST ),\n srcGroup: resolveUrl( this.prefixUrl, navImages.rotateright.GROUP ),\n srcHover: resolveUrl( this.prefixUrl, navImages.rotateright.HOVER ),\n srcDown: resolveUrl( this.prefixUrl, navImages.rotateright.DOWN ),\n onRelease: onRotateRightHandler,\n onFocus: onFocusHandler,\n onBlur: onBlurHandler\n }));\n\n }\n\n if ( useGroup ) {\n this.buttons = new $.ButtonGroup({\n buttons: buttons,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold\n });\n\n this.navControl = this.buttons.element;\n this.addHandler( 'open', $.delegate( this, lightUp ) );\n\n if( this.toolbar ){\n this.toolbar.addControl(\n this.navControl,\n {anchor: this.navigationControlAnchor || $.ControlAnchor.TOP_LEFT}\n );\n } else {\n this.addControl(\n this.navControl,\n {anchor: this.navigationControlAnchor || $.ControlAnchor.TOP_LEFT}\n );\n }\n }\n\n }\n return this;\n },\n\n /**\n * Gets the active page of a sequence\n * @function\n * @return {Number}\n */\n currentPage: function() {\n return this._sequenceIndex;\n },\n\n /**\n * @function\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:page\n */\n goToPage: function( page ){\n if( this.tileSources && page >= 0 && page < this.tileSources.length ){\n /**\n * Raised when the page is changed on a viewer configured with multiple image sources (see {@link OpenSeadragon.Viewer#goToPage}).\n *\n * @event page\n * @memberof OpenSeadragon.Viewer\n * @type {Object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Number} page - The page index.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'page', { page: page } );\n\n this._sequenceIndex = page;\n\n this._updateSequenceButtons( page );\n\n this.open( this.tileSources[ page ] );\n\n if( this.referenceStrip ){\n this.referenceStrip.setFocus( page );\n }\n }\n\n return this;\n },\n\n /**\n * Adds an html element as an overlay to the current viewport. Useful for\n * highlighting words or areas of interest on an image or other zoomable\n * interface. The overlays added via this method are removed when the viewport\n * is closed which include when changing page.\n * @method\n * @param {Element|String|Object} element - A reference to an element or an id for\n * the element which will be overlayed. Or an Object specifying the configuration for the overlay.\n * If using an object, see {@link OpenSeadragon.Overlay} for a list of\n * all available options.\n * @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or\n * rectangle which will be overlayed. This is a viewport relative location.\n * @param {OpenSeadragon.Placement} placement - The position of the\n * viewport which the location coordinates will be treated as relative\n * to.\n * @param {function} onDraw - If supplied the callback is called when the overlay\n * needs to be drawn. It it the responsibility of the callback to do any drawing/positioning.\n * It is passed position, size and element.\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:add-overlay\n */\n addOverlay: function( element, location, placement, onDraw ) {\n var options;\n if( $.isPlainObject( element ) ){\n options = element;\n } else {\n options = {\n element: element,\n location: location,\n placement: placement,\n onDraw: onDraw\n };\n }\n\n element = $.getElement( options.element );\n\n if ( getOverlayIndex( this.currentOverlays, element ) >= 0 ) {\n // they're trying to add a duplicate overlay\n return this;\n }\n\n var overlay = getOverlayObject( this, options);\n this.currentOverlays.push(overlay);\n overlay.drawHTML( this.overlaysContainer, this.viewport );\n\n /**\n * Raised when an overlay is added to the viewer (see {@link OpenSeadragon.Viewer#addOverlay}).\n *\n * @event add-overlay\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Element} element - The overlay element.\n * @property {OpenSeadragon.Point|OpenSeadragon.Rect} location\n * @property {OpenSeadragon.Placement} placement\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'add-overlay', {\n element: element,\n location: options.location,\n placement: options.placement\n });\n return this;\n },\n\n /**\n * Updates the overlay represented by the reference to the element or\n * element id moving it to the new location, relative to the new placement.\n * @method\n * @param {Element|String} element - A reference to an element or an id for\n * the element which is overlayed.\n * @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or\n * rectangle which will be overlayed. This is a viewport relative location.\n * @param {OpenSeadragon.Placement} placement - The position of the\n * viewport which the location coordinates will be treated as relative\n * to.\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:update-overlay\n */\n updateOverlay: function( element, location, placement ) {\n var i;\n\n element = $.getElement( element );\n i = getOverlayIndex( this.currentOverlays, element );\n\n if ( i >= 0 ) {\n this.currentOverlays[ i ].update( location, placement );\n THIS[ this.hash ].forceRedraw = true;\n /**\n * Raised when an overlay's location or placement changes\n * (see {@link OpenSeadragon.Viewer#updateOverlay}).\n *\n * @event update-overlay\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the\n * Viewer which raised the event.\n * @property {Element} element\n * @property {OpenSeadragon.Point|OpenSeadragon.Rect} location\n * @property {OpenSeadragon.Placement} placement\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'update-overlay', {\n element: element,\n location: location,\n placement: placement\n });\n }\n return this;\n },\n\n /**\n * Removes an overlay identified by the reference element or element id\n * and schedules an update.\n * @method\n * @param {Element|String} element - A reference to the element or an\n * element id which represent the ovelay content to be removed.\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:remove-overlay\n */\n removeOverlay: function( element ) {\n var i;\n\n element = $.getElement( element );\n i = getOverlayIndex( this.currentOverlays, element );\n\n if ( i >= 0 ) {\n this.currentOverlays[ i ].destroy();\n this.currentOverlays.splice( i, 1 );\n THIS[ this.hash ].forceRedraw = true;\n /**\n * Raised when an overlay is removed from the viewer\n * (see {@link OpenSeadragon.Viewer#removeOverlay}).\n *\n * @event remove-overlay\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the\n * Viewer which raised the event.\n * @property {Element} element - The overlay element.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'remove-overlay', {\n element: element\n });\n }\n return this;\n },\n\n /**\n * Removes all currently configured Overlays from this Viewer and schedules\n * an update.\n * @method\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:clear-overlay\n */\n clearOverlays: function() {\n while ( this.currentOverlays.length > 0 ) {\n this.currentOverlays.pop().destroy();\n }\n THIS[ this.hash ].forceRedraw = true;\n /**\n * Raised when all overlays are removed from the viewer (see {@link OpenSeadragon.Drawer#clearOverlays}).\n *\n * @event clear-overlay\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'clear-overlay', {} );\n return this;\n },\n\n /**\n * Finds an overlay identified by the reference element or element id\n * and returns it as an object, return null if not found.\n * @method\n * @param {Element|String} element - A reference to the element or an\n * element id which represents the overlay content.\n * @return {OpenSeadragon.Overlay} the matching overlay or null if none found.\n */\n getOverlayById: function( element ) {\n var i;\n\n element = $.getElement( element );\n i = getOverlayIndex( this.currentOverlays, element );\n\n if (i >= 0) {\n return this.currentOverlays[i];\n } else {\n return null;\n }\n },\n\n /**\n * Updates the sequence buttons.\n * @function OpenSeadragon.Viewer.prototype._updateSequenceButtons\n * @private\n * @param {Number} Sequence Value\n */\n _updateSequenceButtons: function( page ) {\n\n if ( this.nextButton ) {\n if(!this.tileSources || this.tileSources.length - 1 === page) {\n //Disable next button\n if ( !this.navPrevNextWrap ) {\n this.nextButton.disable();\n }\n } else {\n this.nextButton.enable();\n }\n }\n if ( this.previousButton ) {\n if ( page > 0 ) {\n //Enable previous button\n this.previousButton.enable();\n } else {\n if ( !this.navPrevNextWrap ) {\n this.previousButton.disable();\n }\n }\n }\n },\n\n /**\n * Display a message in the viewport\n * @function OpenSeadragon.Viewer.prototype._showMessage\n * @private\n * @param {String} text message\n */\n _showMessage: function ( message ) {\n this._hideMessage();\n\n var div = $.makeNeutralElement( \"div\" );\n div.appendChild( document.createTextNode( message ) );\n\n this.messageDiv = $.makeCenteredNode( div );\n\n $.addClass(this.messageDiv, \"openseadragon-message\");\n\n this.container.appendChild( this.messageDiv );\n },\n\n /**\n * Hide any currently displayed viewport message\n * @function OpenSeadragon.Viewer.prototype._hideMessage\n * @private\n */\n _hideMessage: function () {\n var div = this.messageDiv;\n if (div) {\n div.parentNode.removeChild(div);\n delete this.messageDiv;\n }\n },\n\n /**\n * Gets this viewer's gesture settings for the given pointer device type.\n * @method\n * @param {String} type - The pointer device type to get the gesture settings for (\"mouse\", \"touch\", \"pen\", etc.).\n * @return {OpenSeadragon.GestureSettings}\n */\n gestureSettingsByDeviceType: function ( type ) {\n switch ( type ) {\n case 'mouse':\n return this.gestureSettingsMouse;\n case 'touch':\n return this.gestureSettingsTouch;\n case 'pen':\n return this.gestureSettingsPen;\n default:\n return this.gestureSettingsUnknown;\n }\n },\n\n // private\n _drawOverlays: function() {\n var i,\n length = this.currentOverlays.length;\n for ( i = 0; i < length; i++ ) {\n this.currentOverlays[ i ].drawHTML( this.overlaysContainer, this.viewport );\n }\n },\n\n /**\n * Cancel the \"in flight\" images.\n */\n _cancelPendingImages: function() {\n this._loadQueue = [];\n },\n\n /**\n * Removes the reference strip and disables displaying it.\n * @function\n */\n removeReferenceStrip: function() {\n this.showReferenceStrip = false;\n\n if (this.referenceStrip) {\n this.referenceStrip.destroy();\n this.referenceStrip = null;\n }\n },\n\n /**\n * Enables and displays the reference strip based on the currently set tileSources.\n * Works only when the Viewer has sequenceMode set to true.\n * @function\n */\n addReferenceStrip: function() {\n this.showReferenceStrip = true;\n\n if (this.sequenceMode) {\n if (this.referenceStrip) {\n return;\n }\n\n if (this.tileSources.length && this.tileSources.length > 1) {\n this.referenceStrip = new $.ReferenceStrip({\n id: this.referenceStripElement,\n position: this.referenceStripPosition,\n sizeRatio: this.referenceStripSizeRatio,\n scroll: this.referenceStripScroll,\n height: this.referenceStripHeight,\n width: this.referenceStripWidth,\n tileSources: this.tileSources,\n prefixUrl: this.prefixUrl,\n viewer: this\n });\n\n this.referenceStrip.setFocus( this._sequenceIndex );\n }\n } else {\n $.console.warn('Attempting to display a reference strip while \"sequenceMode\" is off.');\n }\n }\n});\n\n\n/**\n * _getSafeElemSize is like getElementSize(), but refuses to return 0 for x or y,\n * which was causing some calling operations to return NaN.\n * @returns {Point}\n * @private\n */\nfunction _getSafeElemSize (oElement) {\n oElement = $.getElement( oElement );\n\n return new $.Point(\n (oElement.clientWidth === 0 ? 1 : oElement.clientWidth),\n (oElement.clientHeight === 0 ? 1 : oElement.clientHeight)\n );\n}\n\n\n/**\n * @function\n * @private\n */\nfunction getTileSourceImplementation( viewer, tileSource, imgOptions, successCallback,\n failCallback ) {\n var _this = viewer;\n\n //allow plain xml strings or json strings to be parsed here\n if ( $.type( tileSource ) == 'string' ) {\n //xml should start with \"<\" and end with \">\"\n if ( tileSource.match( /^\\s*<.*>\\s*$/ ) ) {\n tileSource = $.parseXml( tileSource );\n //json should start with \"{\" or \"[\" and end with \"}\" or \"]\"\n } else if ( tileSource.match(/^\\s*[\\{\\[].*[\\}\\]]\\s*$/ ) ) {\n try {\n var tileSourceJ = $.parseJSON(tileSource);\n tileSource = tileSourceJ;\n } catch (e) {\n //tileSource = tileSource;\n }\n }\n }\n\n function waitUntilReady(tileSource, originalTileSource) {\n if (tileSource.ready) {\n successCallback(tileSource);\n } else {\n tileSource.addHandler('ready', function () {\n successCallback(tileSource);\n });\n tileSource.addHandler('open-failed', function (event) {\n failCallback({\n message: event.message,\n source: originalTileSource\n });\n });\n }\n }\n\n setTimeout( function() {\n if ( $.type( tileSource ) == 'string' ) {\n //If its still a string it means it must be a url at this point\n tileSource = new $.TileSource({\n url: tileSource,\n crossOriginPolicy: imgOptions.crossOriginPolicy !== undefined ?\n imgOptions.crossOriginPolicy : viewer.crossOriginPolicy,\n ajaxWithCredentials: viewer.ajaxWithCredentials,\n ajaxHeaders: viewer.ajaxHeaders,\n useCanvas: viewer.useCanvas,\n success: function( event ) {\n successCallback( event.tileSource );\n }\n });\n tileSource.addHandler( 'open-failed', function( event ) {\n failCallback( event );\n } );\n\n } else if ($.isPlainObject(tileSource) || tileSource.nodeType) {\n if (tileSource.crossOriginPolicy === undefined &&\n (imgOptions.crossOriginPolicy !== undefined || viewer.crossOriginPolicy !== undefined)) {\n tileSource.crossOriginPolicy = imgOptions.crossOriginPolicy !== undefined ?\n imgOptions.crossOriginPolicy : viewer.crossOriginPolicy;\n }\n if (tileSource.ajaxWithCredentials === undefined) {\n tileSource.ajaxWithCredentials = viewer.ajaxWithCredentials;\n }\n if (tileSource.useCanvas === undefined) {\n tileSource.useCanvas = viewer.useCanvas;\n }\n\n if ( $.isFunction( tileSource.getTileUrl ) ) {\n //Custom tile source\n var customTileSource = new $.TileSource( tileSource );\n customTileSource.getTileUrl = tileSource.getTileUrl;\n successCallback( customTileSource );\n } else {\n //inline configuration\n var $TileSource = $.TileSource.determineType( _this, tileSource );\n if ( !$TileSource ) {\n failCallback( {\n message: \"Unable to load TileSource\",\n source: tileSource\n });\n return;\n }\n var options = $TileSource.prototype.configure.apply( _this, [ tileSource ] );\n waitUntilReady(new $TileSource(options), tileSource);\n }\n } else {\n //can assume it's already a tile source implementation\n waitUntilReady(tileSource, tileSource);\n }\n });\n}\n\nfunction getOverlayObject( viewer, overlay ) {\n if ( overlay instanceof $.Overlay ) {\n return overlay;\n }\n\n var element = null;\n if ( overlay.element ) {\n element = $.getElement( overlay.element );\n } else {\n var id = overlay.id ?\n overlay.id :\n \"openseadragon-overlay-\" + Math.floor( Math.random() * 10000000 );\n\n element = $.getElement( overlay.id );\n if ( !element ) {\n element = document.createElement( \"a\" );\n element.href = \"#/overlay/\" + id;\n }\n element.id = id;\n $.addClass( element, overlay.className ?\n overlay.className :\n \"openseadragon-overlay\"\n );\n }\n\n var location = overlay.location;\n var width = overlay.width;\n var height = overlay.height;\n if (!location) {\n var x = overlay.x;\n var y = overlay.y;\n if (overlay.px !== undefined) {\n var rect = viewer.viewport.imageToViewportRectangle(new $.Rect(\n overlay.px,\n overlay.py,\n width || 0,\n height || 0));\n x = rect.x;\n y = rect.y;\n width = width !== undefined ? rect.width : undefined;\n height = height !== undefined ? rect.height : undefined;\n }\n location = new $.Point(x, y);\n }\n\n var placement = overlay.placement;\n if (placement && $.type(placement) === \"string\") {\n placement = $.Placement[overlay.placement.toUpperCase()];\n }\n\n return new $.Overlay({\n element: element,\n location: location,\n placement: placement,\n onDraw: overlay.onDraw,\n checkResize: overlay.checkResize,\n width: width,\n height: height,\n rotationMode: overlay.rotationMode\n });\n}\n\n/**\n * @private\n * @inner\n * Determines the index of the given overlay in the given overlays array.\n */\nfunction getOverlayIndex( overlays, element ) {\n var i;\n for ( i = overlays.length - 1; i >= 0; i-- ) {\n if ( overlays[ i ].element === element ) {\n return i;\n }\n }\n\n return -1;\n}\n\n///////////////////////////////////////////////////////////////////////////////\n// Schedulers provide the general engine for animation\n///////////////////////////////////////////////////////////////////////////////\nfunction scheduleUpdate( viewer, updateFunc ){\n return $.requestAnimationFrame( function(){\n updateFunc( viewer );\n } );\n}\n\n\n//provides a sequence in the fade animation\nfunction scheduleControlsFade( viewer ) {\n $.requestAnimationFrame( function(){\n updateControlsFade( viewer );\n });\n}\n\n\n//initiates an animation to hide the controls\nfunction beginControlsAutoHide( viewer ) {\n if ( !viewer.autoHideControls ) {\n return;\n }\n viewer.controlsShouldFade = true;\n viewer.controlsFadeBeginTime =\n $.now() +\n viewer.controlsFadeDelay;\n\n window.setTimeout( function(){\n scheduleControlsFade( viewer );\n }, viewer.controlsFadeDelay );\n}\n\n\n//determines if fade animation is done or continues the animation\nfunction updateControlsFade( viewer ) {\n var currentTime,\n deltaTime,\n opacity,\n i;\n if ( viewer.controlsShouldFade ) {\n currentTime = $.now();\n deltaTime = currentTime - viewer.controlsFadeBeginTime;\n opacity = 1.0 - deltaTime / viewer.controlsFadeLength;\n\n opacity = Math.min( 1.0, opacity );\n opacity = Math.max( 0.0, opacity );\n\n for ( i = viewer.controls.length - 1; i >= 0; i--) {\n if (viewer.controls[ i ].autoFade) {\n viewer.controls[ i ].setOpacity( opacity );\n }\n }\n\n if ( opacity > 0 ) {\n // fade again\n scheduleControlsFade( viewer );\n }\n }\n}\n\n\n//stop the fade animation on the controls and show them\nfunction abortControlsAutoHide( viewer ) {\n var i;\n viewer.controlsShouldFade = false;\n for ( i = viewer.controls.length - 1; i >= 0; i-- ) {\n viewer.controls[ i ].setOpacity( 1.0 );\n }\n}\n\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Default view event handlers.\n///////////////////////////////////////////////////////////////////////////////\nfunction onFocus(){\n abortControlsAutoHide( this );\n}\n\nfunction onBlur(){\n beginControlsAutoHide( this );\n\n}\n\nfunction onCanvasKeyDown( event ) {\n if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) {\n switch( event.keyCode ){\n case 38://up arrow\n if ( event.shift ) {\n this.viewport.zoomBy(1.1);\n } else {\n this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, -40)));\n }\n this.viewport.applyConstraints();\n return false;\n case 40://down arrow\n if ( event.shift ) {\n this.viewport.zoomBy(0.9);\n } else {\n this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, 40)));\n }\n this.viewport.applyConstraints();\n return false;\n case 37://left arrow\n this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(-40, 0)));\n this.viewport.applyConstraints();\n return false;\n case 39://right arrow\n this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(40, 0)));\n this.viewport.applyConstraints();\n return false;\n default:\n //console.log( 'navigator keycode %s', event.keyCode );\n return true;\n }\n } else {\n return true;\n }\n}\n\nfunction onCanvasKeyPress( event ) {\n if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) {\n switch( event.keyCode ){\n case 43://=|+\n case 61://=|+\n this.viewport.zoomBy(1.1);\n this.viewport.applyConstraints();\n return false;\n case 45://-|_\n this.viewport.zoomBy(0.9);\n this.viewport.applyConstraints();\n return false;\n case 48://0|)\n this.viewport.goHome();\n this.viewport.applyConstraints();\n return false;\n case 119://w\n case 87://W\n if ( event.shift ) {\n this.viewport.zoomBy(1.1);\n } else {\n this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, -40)));\n }\n this.viewport.applyConstraints();\n return false;\n case 115://s\n case 83://S\n if ( event.shift ) {\n this.viewport.zoomBy(0.9);\n } else {\n this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, 40)));\n }\n this.viewport.applyConstraints();\n return false;\n case 97://a\n this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(-40, 0)));\n this.viewport.applyConstraints();\n return false;\n case 100://d\n this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(40, 0)));\n this.viewport.applyConstraints();\n return false;\n default:\n //console.log( 'navigator keycode %s', event.keyCode );\n return true;\n }\n } else {\n return true;\n }\n}\n\nfunction onCanvasClick( event ) {\n var gestureSettings;\n\n var haveKeyboardFocus = document.activeElement == this.canvas;\n\n // If we don't have keyboard focus, request it.\n if ( !haveKeyboardFocus ) {\n this.canvas.focus();\n }\n\n var canvasClickEventArgs = {\n tracker: event.eventSource,\n position: event.position,\n quick: event.quick,\n shift: event.shift,\n originalEvent: event.originalEvent,\n preventDefaultAction: event.preventDefaultAction\n };\n\n /**\n * Raised when a mouse press/release or touch/remove occurs on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-click\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Boolean} quick - True only if the clickDistThreshold and clickTimeThreshold are both passed. Useful for differentiating between clicks and drags.\n * @property {Boolean} shift - True if the shift key was pressed during this event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {Boolean} preventDefaultAction - Set to true to prevent default click to zoom behaviour. Default: false.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-click', canvasClickEventArgs);\n\n if ( !canvasClickEventArgs.preventDefaultAction && this.viewport && event.quick ) {\n gestureSettings = this.gestureSettingsByDeviceType( event.pointerType );\n if ( gestureSettings.clickToZoom ) {\n this.viewport.zoomBy(\n event.shift ? 1.0 / this.zoomPerClick : this.zoomPerClick,\n this.viewport.pointFromPixel( event.position, true )\n );\n this.viewport.applyConstraints();\n }\n }\n}\n\nfunction onCanvasDblClick( event ) {\n var gestureSettings;\n\n if ( !event.preventDefaultAction && this.viewport ) {\n gestureSettings = this.gestureSettingsByDeviceType( event.pointerType );\n if ( gestureSettings.dblClickToZoom ) {\n this.viewport.zoomBy(\n event.shift ? 1.0 / this.zoomPerClick : this.zoomPerClick,\n this.viewport.pointFromPixel( event.position, true )\n );\n this.viewport.applyConstraints();\n }\n }\n /**\n * Raised when a double mouse press/release or touch/remove occurs on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-double-click\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Boolean} shift - True if the shift key was pressed during this event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-double-click', {\n tracker: event.eventSource,\n position: event.position,\n shift: event.shift,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onCanvasDrag( event ) {\n var gestureSettings;\n\n var canvasDragEventArgs = {\n tracker: event.eventSource,\n position: event.position,\n delta: event.delta,\n speed: event.speed,\n direction: event.direction,\n shift: event.shift,\n originalEvent: event.originalEvent,\n preventDefaultAction: event.preventDefaultAction\n };\n\n /**\n * Raised when a mouse or touch drag operation occurs on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-drag\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {OpenSeadragon.Point} delta - The x,y components of the difference between start drag and end drag.\n * @property {Number} speed - Current computed speed, in pixels per second.\n * @property {Number} direction - Current computed direction, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0.\n * @property {Boolean} shift - True if the shift key was pressed during this event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {Boolean} preventDefaultAction - Set to true to prevent default drag behaviour. Default: false.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-drag', canvasDragEventArgs);\n\n if ( !canvasDragEventArgs.preventDefaultAction && this.viewport ) {\n gestureSettings = this.gestureSettingsByDeviceType( event.pointerType );\n if( !this.panHorizontal ){\n event.delta.x = 0;\n }\n if( !this.panVertical ){\n event.delta.y = 0;\n }\n\n if( this.constrainDuringPan ){\n var delta = this.viewport.deltaPointsFromPixels( event.delta.negate() );\n\n this.viewport.centerSpringX.target.value += delta.x;\n this.viewport.centerSpringY.target.value += delta.y;\n\n var bounds = this.viewport.getBounds();\n var constrainedBounds = this.viewport.getConstrainedBounds();\n\n this.viewport.centerSpringX.target.value -= delta.x;\n this.viewport.centerSpringY.target.value -= delta.y;\n\n if (bounds.x != constrainedBounds.x) {\n event.delta.x = 0;\n }\n\n if (bounds.y != constrainedBounds.y) {\n event.delta.y = 0;\n }\n }\n\n this.viewport.panBy( this.viewport.deltaPointsFromPixels( event.delta.negate() ), gestureSettings.flickEnabled && !this.constrainDuringPan);\n }\n}\n\nfunction onCanvasDragEnd( event ) {\n if (!event.preventDefaultAction && this.viewport) {\n var gestureSettings = this.gestureSettingsByDeviceType(event.pointerType);\n if (gestureSettings.flickEnabled &&\n event.speed >= gestureSettings.flickMinSpeed) {\n var amplitudeX = 0;\n if (this.panHorizontal) {\n amplitudeX = gestureSettings.flickMomentum * event.speed *\n Math.cos(event.direction);\n }\n var amplitudeY = 0;\n if (this.panVertical) {\n amplitudeY = gestureSettings.flickMomentum * event.speed *\n Math.sin(event.direction);\n }\n var center = this.viewport.pixelFromPoint(\n this.viewport.getCenter(true));\n var target = this.viewport.pointFromPixel(\n new $.Point(center.x - amplitudeX, center.y - amplitudeY));\n this.viewport.panTo(target, false);\n }\n this.viewport.applyConstraints();\n }\n /**\n * Raised when a mouse or touch drag operation ends on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-drag-end\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Number} speed - Speed at the end of a drag gesture, in pixels per second.\n * @property {Number} direction - Direction at the end of a drag gesture, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0.\n * @property {Boolean} shift - True if the shift key was pressed during this event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent('canvas-drag-end', {\n tracker: event.eventSource,\n position: event.position,\n speed: event.speed,\n direction: event.direction,\n shift: event.shift,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onCanvasEnter( event ) {\n /**\n * Raised when a pointer enters the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-enter\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {String} pointerType - \"mouse\", \"touch\", \"pen\", etc.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @property {Number} pointers - Number of pointers (all types) active in the tracked element.\n * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false.\n * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-enter', {\n tracker: event.eventSource,\n pointerType: event.pointerType,\n position: event.position,\n buttons: event.buttons,\n pointers: event.pointers,\n insideElementPressed: event.insideElementPressed,\n buttonDownAny: event.buttonDownAny,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onCanvasExit( event ) {\n\n if (window.location != window.parent.location){\n $.MouseTracker.resetAllMouseTrackers();\n }\n\n /**\n * Raised when a pointer leaves the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-exit\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {String} pointerType - \"mouse\", \"touch\", \"pen\", etc.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @property {Number} pointers - Number of pointers (all types) active in the tracked element.\n * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false.\n * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-exit', {\n tracker: event.eventSource,\n pointerType: event.pointerType,\n position: event.position,\n buttons: event.buttons,\n pointers: event.pointers,\n insideElementPressed: event.insideElementPressed,\n buttonDownAny: event.buttonDownAny,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onCanvasPress( event ) {\n /**\n * Raised when the primary mouse button is pressed or touch starts on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-press\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {String} pointerType - \"mouse\", \"touch\", \"pen\", etc.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false.\n * @property {Boolean} insideElementReleased - True if the cursor still inside the tracked element when the button was released.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-press', {\n tracker: event.eventSource,\n pointerType: event.pointerType,\n position: event.position,\n insideElementPressed: event.insideElementPressed,\n insideElementReleased: event.insideElementReleased,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onCanvasRelease( event ) {\n /**\n * Raised when the primary mouse button is released or touch ends on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-release\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {String} pointerType - \"mouse\", \"touch\", \"pen\", etc.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false.\n * @property {Boolean} insideElementReleased - True if the cursor still inside the tracked element when the button was released.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-release', {\n tracker: event.eventSource,\n pointerType: event.pointerType,\n position: event.position,\n insideElementPressed: event.insideElementPressed,\n insideElementReleased: event.insideElementReleased,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onCanvasNonPrimaryPress( event ) {\n /**\n * Raised when any non-primary pointer button is pressed on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-nonprimary-press\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {String} pointerType - \"mouse\", \"touch\", \"pen\", etc.\n * @property {Number} button - Button which caused the event.\n * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.\n * @property {Number} buttons - Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-nonprimary-press', {\n tracker: event.eventSource,\n position: event.position,\n pointerType: event.pointerType,\n button: event.button,\n buttons: event.buttons,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onCanvasNonPrimaryRelease( event ) {\n /**\n * Raised when any non-primary pointer button is released on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-nonprimary-release\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {String} pointerType - \"mouse\", \"touch\", \"pen\", etc.\n * @property {Number} button - Button which caused the event.\n * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.\n * @property {Number} buttons - Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-nonprimary-release', {\n tracker: event.eventSource,\n position: event.position,\n pointerType: event.pointerType,\n button: event.button,\n buttons: event.buttons,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onCanvasPinch( event ) {\n var gestureSettings,\n centerPt,\n lastCenterPt,\n panByPt;\n\n if ( !event.preventDefaultAction && this.viewport ) {\n gestureSettings = this.gestureSettingsByDeviceType( event.pointerType );\n if ( gestureSettings.pinchToZoom ) {\n centerPt = this.viewport.pointFromPixel( event.center, true );\n lastCenterPt = this.viewport.pointFromPixel( event.lastCenter, true );\n panByPt = lastCenterPt.minus( centerPt );\n if( !this.panHorizontal ) {\n panByPt.x = 0;\n }\n if( !this.panVertical ) {\n panByPt.y = 0;\n }\n this.viewport.zoomBy( event.distance / event.lastDistance, centerPt, true );\n this.viewport.panBy( panByPt, true );\n this.viewport.applyConstraints();\n }\n if ( gestureSettings.pinchRotate ) {\n // Pinch rotate\n var angle1 = Math.atan2(event.gesturePoints[0].currentPos.y - event.gesturePoints[1].currentPos.y,\n event.gesturePoints[0].currentPos.x - event.gesturePoints[1].currentPos.x);\n var angle2 = Math.atan2(event.gesturePoints[0].lastPos.y - event.gesturePoints[1].lastPos.y,\n event.gesturePoints[0].lastPos.x - event.gesturePoints[1].lastPos.x);\n this.viewport.setRotation(this.viewport.getRotation() + ((angle1 - angle2) * (180 / Math.PI)));\n }\n }\n /**\n * Raised when a pinch event occurs on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-pinch\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {Array.} gesturePoints - Gesture points associated with the gesture. Velocity data can be found here.\n * @property {OpenSeadragon.Point} lastCenter - The previous center point of the two pinch contact points relative to the tracked element.\n * @property {OpenSeadragon.Point} center - The center point of the two pinch contact points relative to the tracked element.\n * @property {Number} lastDistance - The previous distance between the two pinch contact points in CSS pixels.\n * @property {Number} distance - The distance between the two pinch contact points in CSS pixels.\n * @property {Boolean} shift - True if the shift key was pressed during this event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent('canvas-pinch', {\n tracker: event.eventSource,\n gesturePoints: event.gesturePoints,\n lastCenter: event.lastCenter,\n center: event.center,\n lastDistance: event.lastDistance,\n distance: event.distance,\n shift: event.shift,\n originalEvent: event.originalEvent\n });\n //cancels event\n return false;\n}\n\nfunction onCanvasScroll( event ) {\n var gestureSettings,\n factor,\n thisScrollTime,\n deltaScrollTime;\n\n /* Certain scroll devices fire the scroll event way too fast so we are injecting a simple adjustment to keep things\n * partially normalized. If we have already fired an event within the last 'minScrollDelta' milliseconds we skip\n * this one and wait for the next event. */\n thisScrollTime = $.now();\n deltaScrollTime = thisScrollTime - this._lastScrollTime;\n if (deltaScrollTime > this.minScrollDeltaTime) {\n this._lastScrollTime = thisScrollTime;\n\n if ( !event.preventDefaultAction && this.viewport ) {\n gestureSettings = this.gestureSettingsByDeviceType( event.pointerType );\n if ( gestureSettings.scrollToZoom ) {\n factor = Math.pow( this.zoomPerScroll, event.scroll );\n this.viewport.zoomBy(\n factor,\n this.viewport.pointFromPixel( event.position, true )\n );\n this.viewport.applyConstraints();\n }\n }\n /**\n * Raised when a scroll event occurs on the {@link OpenSeadragon.Viewer#canvas} element (mouse wheel).\n *\n * @event canvas-scroll\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Number} scroll - The scroll delta for the event.\n * @property {Boolean} shift - True if the shift key was pressed during this event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-scroll', {\n tracker: event.eventSource,\n position: event.position,\n scroll: event.scroll,\n shift: event.shift,\n originalEvent: event.originalEvent\n });\n if (gestureSettings && gestureSettings.scrollToZoom) {\n //cancels event\n return false;\n }\n }\n else {\n gestureSettings = this.gestureSettingsByDeviceType( event.pointerType );\n if (gestureSettings && gestureSettings.scrollToZoom) {\n return false; // We are swallowing this event\n }\n }\n}\n\nfunction onContainerEnter( event ) {\n THIS[ this.hash ].mouseInside = true;\n abortControlsAutoHide( this );\n /**\n * Raised when the cursor enters the {@link OpenSeadragon.Viewer#container} element.\n *\n * @event container-enter\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @property {Number} pointers - Number of pointers (all types) active in the tracked element.\n * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false.\n * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'container-enter', {\n tracker: event.eventSource,\n position: event.position,\n buttons: event.buttons,\n pointers: event.pointers,\n insideElementPressed: event.insideElementPressed,\n buttonDownAny: event.buttonDownAny,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onContainerExit( event ) {\n if ( event.pointers < 1 ) {\n THIS[ this.hash ].mouseInside = false;\n if ( !THIS[ this.hash ].animating ) {\n beginControlsAutoHide( this );\n }\n }\n /**\n * Raised when the cursor leaves the {@link OpenSeadragon.Viewer#container} element.\n *\n * @event container-exit\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @property {Number} pointers - Number of pointers (all types) active in the tracked element.\n * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false.\n * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'container-exit', {\n tracker: event.eventSource,\n position: event.position,\n buttons: event.buttons,\n pointers: event.pointers,\n insideElementPressed: event.insideElementPressed,\n buttonDownAny: event.buttonDownAny,\n originalEvent: event.originalEvent\n });\n}\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Page update routines ( aka Views - for future reference )\n///////////////////////////////////////////////////////////////////////////////\n\nfunction updateMulti( viewer ) {\n updateOnce( viewer );\n\n // Request the next frame, unless we've been closed\n if ( viewer.isOpen() ) {\n viewer._updateRequestId = scheduleUpdate( viewer, updateMulti );\n } else {\n viewer._updateRequestId = false;\n }\n}\n\nfunction updateOnce( viewer ) {\n\n //viewer.profiler.beginUpdate();\n\n if (viewer._opening) {\n return;\n }\n\n if (viewer.autoResize) {\n var containerSize = _getSafeElemSize(viewer.container);\n var prevContainerSize = THIS[viewer.hash].prevContainerSize;\n if (!containerSize.equals(prevContainerSize)) {\n var viewport = viewer.viewport;\n if (viewer.preserveImageSizeOnResize) {\n var resizeRatio = prevContainerSize.x / containerSize.x;\n var zoom = viewport.getZoom() * resizeRatio;\n var center = viewport.getCenter();\n viewport.resize(containerSize, false);\n viewport.zoomTo(zoom, null, true);\n viewport.panTo(center, true);\n } else {\n // maintain image position\n var oldBounds = viewport.getBounds();\n viewport.resize(containerSize, true);\n viewport.fitBoundsWithConstraints(oldBounds, true);\n }\n THIS[viewer.hash].prevContainerSize = containerSize;\n THIS[viewer.hash].forceRedraw = true;\n }\n }\n\n var viewportChange = viewer.viewport.update();\n var animated = viewer.world.update() || viewportChange;\n\n if (viewportChange) {\n /**\n * Raised when any spring animation update occurs (zoom, pan, etc.),\n * before the viewer has drawn the new location.\n *\n * @event viewport-change\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n viewer.raiseEvent('viewport-change');\n }\n\n if( viewer.referenceStrip ){\n animated = viewer.referenceStrip.update( viewer.viewport ) || animated;\n }\n\n if ( !THIS[ viewer.hash ].animating && animated ) {\n /**\n * Raised when any spring animation starts (zoom, pan, etc.).\n *\n * @event animation-start\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n viewer.raiseEvent( \"animation-start\" );\n abortControlsAutoHide( viewer );\n }\n\n if ( animated || THIS[ viewer.hash ].forceRedraw || viewer.world.needsDraw() ) {\n drawWorld( viewer );\n viewer._drawOverlays();\n if( viewer.navigator ){\n viewer.navigator.update( viewer.viewport );\n }\n\n THIS[ viewer.hash ].forceRedraw = false;\n\n if (animated) {\n /**\n * Raised when any spring animation update occurs (zoom, pan, etc.),\n * after the viewer has drawn the new location.\n *\n * @event animation\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n viewer.raiseEvent( \"animation\" );\n }\n }\n\n if ( THIS[ viewer.hash ].animating && !animated ) {\n /**\n * Raised when any spring animation ends (zoom, pan, etc.).\n *\n * @event animation-finish\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n viewer.raiseEvent( \"animation-finish\" );\n\n if ( !THIS[ viewer.hash ].mouseInside ) {\n beginControlsAutoHide( viewer );\n }\n }\n\n THIS[ viewer.hash ].animating = animated;\n\n //viewer.profiler.endUpdate();\n}\n\nfunction drawWorld( viewer ) {\n viewer.imageLoader.clear();\n viewer.drawer.clear();\n viewer.world.draw();\n\n /**\n * - Needs documentation -\n *\n * @event update-viewport\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n viewer.raiseEvent( 'update-viewport', {} );\n}\n\n///////////////////////////////////////////////////////////////////////////////\n// Navigation Controls\n///////////////////////////////////////////////////////////////////////////////\nfunction resolveUrl( prefix, url ) {\n return prefix ? prefix + url : url;\n}\n\n\n\nfunction beginZoomingIn() {\n THIS[ this.hash ].lastZoomTime = $.now();\n THIS[ this.hash ].zoomFactor = this.zoomPerSecond;\n THIS[ this.hash ].zooming = true;\n scheduleZoom( this );\n}\n\n\nfunction beginZoomingOut() {\n THIS[ this.hash ].lastZoomTime = $.now();\n THIS[ this.hash ].zoomFactor = 1.0 / this.zoomPerSecond;\n THIS[ this.hash ].zooming = true;\n scheduleZoom( this );\n}\n\n\nfunction endZooming() {\n THIS[ this.hash ].zooming = false;\n}\n\n\nfunction scheduleZoom( viewer ) {\n $.requestAnimationFrame( $.delegate( viewer, doZoom ) );\n}\n\n\nfunction doZoom() {\n var currentTime,\n deltaTime,\n adjustedFactor;\n\n if ( THIS[ this.hash ].zooming && this.viewport) {\n currentTime = $.now();\n deltaTime = currentTime - THIS[ this.hash ].lastZoomTime;\n adjustedFactor = Math.pow( THIS[ this.hash ].zoomFactor, deltaTime / 1000 );\n\n this.viewport.zoomBy( adjustedFactor );\n this.viewport.applyConstraints();\n THIS[ this.hash ].lastZoomTime = currentTime;\n scheduleZoom( this );\n }\n}\n\n\nfunction doSingleZoomIn() {\n if ( this.viewport ) {\n THIS[ this.hash ].zooming = false;\n this.viewport.zoomBy(\n this.zoomPerClick / 1.0\n );\n this.viewport.applyConstraints();\n }\n}\n\n\nfunction doSingleZoomOut() {\n if ( this.viewport ) {\n THIS[ this.hash ].zooming = false;\n this.viewport.zoomBy(\n 1.0 / this.zoomPerClick\n );\n this.viewport.applyConstraints();\n }\n}\n\n\nfunction lightUp() {\n this.buttons.emulateEnter();\n this.buttons.emulateExit();\n}\n\n\nfunction onHome() {\n if ( this.viewport ) {\n this.viewport.goHome();\n }\n}\n\n\nfunction onFullScreen() {\n if ( this.isFullPage() && !$.isFullScreen() ) {\n // Is fullPage but not fullScreen\n this.setFullPage( false );\n } else {\n this.setFullScreen( !this.isFullPage() );\n }\n // correct for no mouseout event on change\n if ( this.buttons ) {\n this.buttons.emulateExit();\n }\n this.fullPageButton.element.focus();\n if ( this.viewport ) {\n this.viewport.applyConstraints();\n }\n}\n\n/**\n * Note: The current rotation feature is limited to 90 degree turns.\n */\nfunction onRotateLeft() {\n if ( this.viewport ) {\n var currRotation = this.viewport.getRotation();\n if (currRotation === 0) {\n currRotation = 270;\n }\n else {\n currRotation -= 90;\n }\n this.viewport.setRotation(currRotation);\n }\n}\n\n/**\n * Note: The current rotation feature is limited to 90 degree turns.\n */\nfunction onRotateRight() {\n if ( this.viewport ) {\n var currRotation = this.viewport.getRotation();\n if (currRotation === 270) {\n currRotation = 0;\n }\n else {\n currRotation += 90;\n }\n this.viewport.setRotation(currRotation);\n }\n}\n\n\nfunction onPrevious(){\n var previous = this._sequenceIndex - 1;\n if(this.navPrevNextWrap && previous < 0){\n previous += this.tileSources.length;\n }\n this.goToPage( previous );\n}\n\n\nfunction onNext(){\n var next = this._sequenceIndex + 1;\n if(this.navPrevNextWrap && next >= this.tileSources.length){\n next = 0;\n }\n this.goToPage( next );\n}\n\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - Navigator\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class Navigator\n * @classdesc The Navigator provides a small view of the current image as fixed\n * while representing the viewport as a moving box serving as a frame\n * of reference in the larger viewport as to which portion of the image\n * is currently being examined. The navigator's viewport can be interacted\n * with using the keyboard or the mouse.\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.Viewer\n * @extends OpenSeadragon.EventSource\n * @param {Object} options\n */\n$.Navigator = function( options ){\n\n var viewer = options.viewer,\n _this = this,\n viewerSize,\n navigatorSize;\n\n //We may need to create a new element and id if they did not\n //provide the id for the existing element\n if( !options.id ){\n options.id = 'navigator-' + $.now();\n this.element = $.makeNeutralElement( \"div\" );\n options.controlOptions = {\n anchor: $.ControlAnchor.TOP_RIGHT,\n attachToViewer: true,\n autoFade: options.autoFade\n };\n\n if( options.position ){\n if( 'BOTTOM_RIGHT' == options.position ){\n options.controlOptions.anchor = $.ControlAnchor.BOTTOM_RIGHT;\n } else if( 'BOTTOM_LEFT' == options.position ){\n options.controlOptions.anchor = $.ControlAnchor.BOTTOM_LEFT;\n } else if( 'TOP_RIGHT' == options.position ){\n options.controlOptions.anchor = $.ControlAnchor.TOP_RIGHT;\n } else if( 'TOP_LEFT' == options.position ){\n options.controlOptions.anchor = $.ControlAnchor.TOP_LEFT;\n } else if( 'ABSOLUTE' == options.position ){\n options.controlOptions.anchor = $.ControlAnchor.ABSOLUTE;\n options.controlOptions.top = options.top;\n options.controlOptions.left = options.left;\n options.controlOptions.height = options.height;\n options.controlOptions.width = options.width;\n }\n }\n\n } else {\n this.element = document.getElementById( options.id );\n options.controlOptions = {\n anchor: $.ControlAnchor.NONE,\n attachToViewer: false,\n autoFade: false\n };\n }\n this.element.id = options.id;\n this.element.className += ' navigator';\n\n options = $.extend( true, {\n sizeRatio: $.DEFAULT_SETTINGS.navigatorSizeRatio\n }, options, {\n element: this.element,\n tabIndex: -1, // No keyboard navigation, omit from tab order\n //These need to be overridden to prevent recursion since\n //the navigator is a viewer and a viewer has a navigator\n showNavigator: false,\n mouseNavEnabled: false,\n showNavigationControl: false,\n showSequenceControl: false,\n immediateRender: true,\n blendTime: 0,\n animationTime: 0,\n autoResize: options.autoResize,\n // prevent resizing the navigator from adding unwanted space around the image\n minZoomImageRatio: 1.0\n });\n\n options.minPixelRatio = this.minPixelRatio = viewer.minPixelRatio;\n\n $.setElementTouchActionNone( this.element );\n\n this.borderWidth = 2;\n //At some browser magnification levels the display regions lines up correctly, but at some there appears to\n //be a one pixel gap.\n this.fudge = new $.Point(1, 1);\n this.totalBorderWidths = new $.Point(this.borderWidth * 2, this.borderWidth * 2).minus(this.fudge);\n\n\n if ( options.controlOptions.anchor != $.ControlAnchor.NONE ) {\n (function( style, borderWidth ){\n style.margin = '0px';\n style.border = borderWidth + 'px solid #555';\n style.padding = '0px';\n style.background = '#000';\n style.opacity = 0.8;\n style.overflow = 'hidden';\n }( this.element.style, this.borderWidth));\n }\n\n this.displayRegion = $.makeNeutralElement( \"div\" );\n this.displayRegion.id = this.element.id + '-displayregion';\n this.displayRegion.className = 'displayregion';\n\n (function( style, borderWidth ){\n style.position = 'relative';\n style.top = '0px';\n style.left = '0px';\n style.fontSize = '0px';\n style.overflow = 'hidden';\n style.border = borderWidth + 'px solid #900';\n style.margin = '0px';\n style.padding = '0px';\n //TODO: IE doesnt like this property being set\n //try{ style.outline = '2px auto #909'; }catch(e){/*ignore*/}\n\n style.background = 'transparent';\n\n // We use square bracket notation on the statement below, because float is a keyword.\n // This is important for the Google Closure compiler, if nothing else.\n /*jshint sub:true */\n style['float'] = 'left'; //Webkit\n\n style.cssFloat = 'left'; //Firefox\n style.styleFloat = 'left'; //IE\n style.zIndex = 999999999;\n style.cursor = 'default';\n }( this.displayRegion.style, this.borderWidth ));\n\n this.displayRegionContainer = $.makeNeutralElement(\"div\");\n this.displayRegionContainer.id = this.element.id + '-displayregioncontainer';\n this.displayRegionContainer.className = \"displayregioncontainer\";\n this.displayRegionContainer.style.width = \"100%\";\n this.displayRegionContainer.style.height = \"100%\";\n\n viewer.addControl(\n this.element,\n options.controlOptions\n );\n\n this._resizeWithViewer = options.controlOptions.anchor != $.ControlAnchor.ABSOLUTE &&\n options.controlOptions.anchor != $.ControlAnchor.NONE;\n\n if ( this._resizeWithViewer ) {\n if ( options.width && options.height ) {\n this.element.style.height = typeof (options.height) == \"number\" ? (options.height + 'px') : options.height;\n this.element.style.width = typeof (options.width) == \"number\" ? (options.width + 'px') : options.width;\n } else {\n viewerSize = $.getElementSize( viewer.element );\n this.element.style.height = Math.round( viewerSize.y * options.sizeRatio ) + 'px';\n this.element.style.width = Math.round( viewerSize.x * options.sizeRatio ) + 'px';\n this.oldViewerSize = viewerSize;\n }\n navigatorSize = $.getElementSize( this.element );\n this.elementArea = navigatorSize.x * navigatorSize.y;\n }\n\n this.oldContainerSize = new $.Point( 0, 0 );\n\n $.Viewer.apply( this, [ options ] );\n\n this.displayRegionContainer.appendChild(this.displayRegion);\n this.element.getElementsByTagName('div')[0].appendChild(this.displayRegionContainer);\n\n function rotate(degrees) {\n _setTransformRotate(_this.displayRegionContainer, degrees);\n _setTransformRotate(_this.displayRegion, -degrees);\n _this.viewport.setRotation(degrees);\n }\n if (options.navigatorRotate) {\n var degrees = options.viewer.viewport ?\n options.viewer.viewport.getRotation() :\n options.viewer.degrees || 0;\n rotate(degrees);\n options.viewer.addHandler(\"rotate\", function (args) {\n rotate(args.degrees);\n });\n }\n\n // Remove the base class' (Viewer's) innerTracker and replace it with our own\n this.innerTracker.destroy();\n this.innerTracker = new $.MouseTracker({\n element: this.element,\n dragHandler: $.delegate( this, onCanvasDrag ),\n clickHandler: $.delegate( this, onCanvasClick ),\n releaseHandler: $.delegate( this, onCanvasRelease ),\n scrollHandler: $.delegate( this, onCanvasScroll )\n });\n\n this.addHandler(\"reset-size\", function() {\n if (_this.viewport) {\n _this.viewport.goHome(true);\n }\n });\n\n viewer.world.addHandler(\"item-index-change\", function(event) {\n window.setTimeout(function(){\n var item = _this.world.getItemAt(event.previousIndex);\n _this.world.setItemIndex(item, event.newIndex);\n }, 1);\n });\n\n viewer.world.addHandler(\"remove-item\", function(event) {\n var theirItem = event.item;\n var myItem = _this._getMatchingItem(theirItem);\n if (myItem) {\n _this.world.removeItem(myItem);\n }\n });\n\n this.update(viewer.viewport);\n};\n\n$.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.Navigator.prototype */{\n\n /**\n * Used to notify the navigator when its size has changed.\n * Especially useful when {@link OpenSeadragon.Options}.navigatorAutoResize is set to false and the navigator is resizable.\n * @function\n */\n updateSize: function () {\n if ( this.viewport ) {\n var containerSize = new $.Point(\n (this.container.clientWidth === 0 ? 1 : this.container.clientWidth),\n (this.container.clientHeight === 0 ? 1 : this.container.clientHeight)\n );\n\n if ( !containerSize.equals( this.oldContainerSize ) ) {\n this.viewport.resize( containerSize, true );\n this.viewport.goHome(true);\n this.oldContainerSize = containerSize;\n this.drawer.clear();\n this.world.draw();\n }\n }\n },\n\n /**\n * Used to update the navigator minimap's viewport rectangle when a change in the viewer's viewport occurs.\n * @function\n * @param {OpenSeadragon.Viewport} The viewport this navigator is tracking.\n */\n update: function( viewport ) {\n\n var viewerSize,\n newWidth,\n newHeight,\n bounds,\n topleft,\n bottomright;\n\n viewerSize = $.getElementSize( this.viewer.element );\n if ( this._resizeWithViewer && viewerSize.x && viewerSize.y && !viewerSize.equals( this.oldViewerSize ) ) {\n this.oldViewerSize = viewerSize;\n\n if ( this.maintainSizeRatio || !this.elementArea) {\n newWidth = viewerSize.x * this.sizeRatio;\n newHeight = viewerSize.y * this.sizeRatio;\n } else {\n newWidth = Math.sqrt(this.elementArea * (viewerSize.x / viewerSize.y));\n newHeight = this.elementArea / newWidth;\n }\n\n this.element.style.width = Math.round( newWidth ) + 'px';\n this.element.style.height = Math.round( newHeight ) + 'px';\n\n if (!this.elementArea) {\n this.elementArea = newWidth * newHeight;\n }\n\n this.updateSize();\n }\n\n if (viewport && this.viewport) {\n bounds = viewport.getBoundsNoRotate(true);\n topleft = this.viewport.pixelFromPointNoRotate(bounds.getTopLeft(), false);\n bottomright = this.viewport.pixelFromPointNoRotate(bounds.getBottomRight(), false)\n .minus( this.totalBorderWidths );\n\n //update style for navigator-box\n var style = this.displayRegion.style;\n style.display = this.world.getItemCount() ? 'block' : 'none';\n\n style.top = Math.round( topleft.y ) + 'px';\n style.left = Math.round( topleft.x ) + 'px';\n\n var width = Math.abs( topleft.x - bottomright.x );\n var height = Math.abs( topleft.y - bottomright.y );\n // make sure width and height are non-negative so IE doesn't throw\n style.width = Math.round( Math.max( width, 0 ) ) + 'px';\n style.height = Math.round( Math.max( height, 0 ) ) + 'px';\n }\n\n },\n\n // overrides Viewer.addTiledImage\n addTiledImage: function(options) {\n var _this = this;\n\n var original = options.originalTiledImage;\n delete options.original;\n\n var optionsClone = $.extend({}, options, {\n success: function(event) {\n var myItem = event.item;\n myItem._originalForNavigator = original;\n _this._matchBounds(myItem, original, true);\n\n function matchBounds() {\n _this._matchBounds(myItem, original);\n }\n\n function matchOpacity() {\n _this._matchOpacity(myItem, original);\n }\n\n function matchCompositeOperation() {\n _this._matchCompositeOperation(myItem, original);\n }\n\n original.addHandler('bounds-change', matchBounds);\n original.addHandler('clip-change', matchBounds);\n original.addHandler('opacity-change', matchOpacity);\n original.addHandler('composite-operation-change', matchCompositeOperation);\n }\n });\n\n return $.Viewer.prototype.addTiledImage.apply(this, [optionsClone]);\n },\n\n // private\n _getMatchingItem: function(theirItem) {\n var count = this.world.getItemCount();\n var item;\n for (var i = 0; i < count; i++) {\n item = this.world.getItemAt(i);\n if (item._originalForNavigator === theirItem) {\n return item;\n }\n }\n\n return null;\n },\n\n // private\n _matchBounds: function(myItem, theirItem, immediately) {\n var bounds = theirItem.getBoundsNoRotate();\n myItem.setPosition(bounds.getTopLeft(), immediately);\n myItem.setWidth(bounds.width, immediately);\n myItem.setRotation(theirItem.getRotation(), immediately);\n myItem.setClip(theirItem.getClip());\n },\n\n // private\n _matchOpacity: function(myItem, theirItem) {\n myItem.setOpacity(theirItem.opacity);\n },\n\n // private\n _matchCompositeOperation: function(myItem, theirItem) {\n myItem.setCompositeOperation(theirItem.compositeOperation);\n }\n});\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onCanvasClick( event ) {\n if ( event.quick && this.viewer.viewport ) {\n this.viewer.viewport.panTo(this.viewport.pointFromPixel(event.position));\n this.viewer.viewport.applyConstraints();\n }\n}\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onCanvasDrag( event ) {\n if ( this.viewer.viewport ) {\n if( !this.panHorizontal ){\n event.delta.x = 0;\n }\n if( !this.panVertical ){\n event.delta.y = 0;\n }\n this.viewer.viewport.panBy(\n this.viewport.deltaPointsFromPixels(\n event.delta\n )\n );\n if( this.viewer.constrainDuringPan ){\n this.viewer.viewport.applyConstraints();\n }\n }\n}\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onCanvasRelease( event ) {\n if ( event.insideElementPressed && this.viewer.viewport ) {\n this.viewer.viewport.applyConstraints();\n }\n}\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onCanvasScroll( event ) {\n /**\n * Raised when a scroll event occurs on the {@link OpenSeadragon.Viewer#navigator} element (mouse wheel, touch pinch, etc.).\n *\n * @event navigator-scroll\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Number} scroll - The scroll delta for the event.\n * @property {Boolean} shift - True if the shift key was pressed during this event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.viewer.raiseEvent( 'navigator-scroll', {\n tracker: event.eventSource,\n position: event.position,\n scroll: event.scroll,\n shift: event.shift,\n originalEvent: event.originalEvent\n });\n\n //dont scroll the page up and down if the user is scrolling\n //in the navigator\n return false;\n}\n\n/**\n * @function\n * @private\n * @param {Object} element\n * @param {Number} degrees\n */\nfunction _setTransformRotate (element, degrees) {\n element.style.webkitTransform = \"rotate(\" + degrees + \"deg)\";\n element.style.mozTransform = \"rotate(\" + degrees + \"deg)\";\n element.style.msTransform = \"rotate(\" + degrees + \"deg)\";\n element.style.oTransform = \"rotate(\" + degrees + \"deg)\";\n element.style.transform = \"rotate(\" + degrees + \"deg)\";\n}\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - getString/setString\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n//TODO: I guess this is where the i18n needs to be reimplemented. I'll look\n// into existing patterns for i18n in javascript but i think that mimicking\n// pythons gettext might be a reasonable approach.\nvar I18N = {\n Errors: {\n Dzc: \"Sorry, we don't support Deep Zoom Collections!\",\n Dzi: \"Hmm, this doesn't appear to be a valid Deep Zoom Image.\",\n Xml: \"Hmm, this doesn't appear to be a valid Deep Zoom Image.\",\n ImageFormat: \"Sorry, we don't support {0}-based Deep Zoom Images.\",\n Security: \"It looks like a security restriction stopped us from \" +\n \"loading this Deep Zoom Image.\",\n Status: \"This space unintentionally left blank ({0} {1}).\",\n OpenFailed: \"Unable to open {0}: {1}\"\n },\n\n Tooltips: {\n FullPage: \"Toggle full page\",\n Home: \"Go home\",\n ZoomIn: \"Zoom in\",\n ZoomOut: \"Zoom out\",\n NextPage: \"Next page\",\n PreviousPage: \"Previous page\",\n RotateLeft: \"Rotate left\",\n RotateRight: \"Rotate right\"\n }\n};\n\n$.extend( $, /** @lends OpenSeadragon */{\n\n /**\n * @function\n * @param {String} property\n */\n getString: function( prop ) {\n\n var props = prop.split('.'),\n string = null,\n args = arguments,\n container = I18N,\n i;\n\n for (i = 0; i < props.length - 1; i++) {\n // in case not a subproperty\n container = container[ props[ i ] ] || {};\n }\n string = container[ props[ i ] ];\n\n if ( typeof( string ) != \"string\" ) {\n $.console.log( \"Untranslated source string:\", prop );\n string = \"\"; // FIXME: this breaks gettext()-style convention, which would return source\n }\n\n return string.replace(/\\{\\d+\\}/g, function(capture) {\n var i = parseInt( capture.match( /\\d+/ ), 10 ) + 1;\n return i < args.length ?\n args[ i ] :\n \"\";\n });\n },\n\n /**\n * @function\n * @param {String} property\n * @param {*} value\n */\n setString: function( prop, value ) {\n\n var props = prop.split('.'),\n container = I18N,\n i;\n\n for ( i = 0; i < props.length - 1; i++ ) {\n if ( !container[ props[ i ] ] ) {\n container[ props[ i ] ] = {};\n }\n container = container[ props[ i ] ];\n }\n\n container[ props[ i ] ] = value;\n }\n\n});\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - Point\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class Point\n * @classdesc A Point is really used as a 2-dimensional vector, equally useful for\n * representing a point on a plane, or the height and width of a plane\n * not requiring any other frame of reference.\n *\n * @memberof OpenSeadragon\n * @param {Number} [x] The vector component 'x'. Defaults to the origin at 0.\n * @param {Number} [y] The vector component 'y'. Defaults to the origin at 0.\n */\n$.Point = function( x, y ) {\n /**\n * The vector component 'x'.\n * @member {Number} x\n * @memberof OpenSeadragon.Point#\n */\n this.x = typeof ( x ) == \"number\" ? x : 0;\n /**\n * The vector component 'y'.\n * @member {Number} y\n * @memberof OpenSeadragon.Point#\n */\n this.y = typeof ( y ) == \"number\" ? y : 0;\n};\n\n/** @lends OpenSeadragon.Point.prototype */\n$.Point.prototype = {\n /**\n * @function\n * @returns {OpenSeadragon.Point} a duplicate of this Point\n */\n clone: function() {\n return new $.Point(this.x, this.y);\n },\n\n /**\n * Add another Point to this point and return a new Point.\n * @function\n * @param {OpenSeadragon.Point} point The point to add vector components.\n * @returns {OpenSeadragon.Point} A new point representing the sum of the\n * vector components\n */\n plus: function( point ) {\n return new $.Point(\n this.x + point.x,\n this.y + point.y\n );\n },\n\n /**\n * Substract another Point to this point and return a new Point.\n * @function\n * @param {OpenSeadragon.Point} point The point to substract vector components.\n * @returns {OpenSeadragon.Point} A new point representing the substraction of the\n * vector components\n */\n minus: function( point ) {\n return new $.Point(\n this.x - point.x,\n this.y - point.y\n );\n },\n\n /**\n * Multiply this point by a factor and return a new Point.\n * @function\n * @param {Number} factor The factor to multiply vector components.\n * @returns {OpenSeadragon.Point} A new point representing the multiplication\n * of the vector components by the factor\n */\n times: function( factor ) {\n return new $.Point(\n this.x * factor,\n this.y * factor\n );\n },\n\n /**\n * Divide this point by a factor and return a new Point.\n * @function\n * @param {Number} factor The factor to divide vector components.\n * @returns {OpenSeadragon.Point} A new point representing the division of the\n * vector components by the factor\n */\n divide: function( factor ) {\n return new $.Point(\n this.x / factor,\n this.y / factor\n );\n },\n\n /**\n * Compute the opposite of this point and return a new Point.\n * @function\n * @returns {OpenSeadragon.Point} A new point representing the opposite of the\n * vector components\n */\n negate: function() {\n return new $.Point( -this.x, -this.y );\n },\n\n /**\n * Compute the distance between this point and another point.\n * @function\n * @param {OpenSeadragon.Point} point The point to compute the distance with.\n * @returns {Number} The distance between the 2 points\n */\n distanceTo: function( point ) {\n return Math.sqrt(\n Math.pow( this.x - point.x, 2 ) +\n Math.pow( this.y - point.y, 2 )\n );\n },\n\n /**\n * Compute the squared distance between this point and another point.\n * Useful for optimizing things like comparing distances.\n * @function\n * @param {OpenSeadragon.Point} point The point to compute the squared distance with.\n * @returns {Number} The squared distance between the 2 points\n */\n squaredDistanceTo: function( point ) {\n return Math.pow( this.x - point.x, 2 ) +\n Math.pow( this.y - point.y, 2 );\n },\n\n /**\n * Apply a function to each coordinate of this point and return a new point.\n * @function\n * @param {function} func The function to apply to each coordinate.\n * @returns {OpenSeadragon.Point} A new point with the coordinates computed\n * by the specified function\n */\n apply: function( func ) {\n return new $.Point( func( this.x ), func( this.y ) );\n },\n\n /**\n * Check if this point is equal to another one.\n * @function\n * @param {OpenSeadragon.Point} point The point to compare this point with.\n * @returns {Boolean} true if they are equal, false otherwise.\n */\n equals: function( point ) {\n return (\n point instanceof $.Point\n ) && (\n this.x === point.x\n ) && (\n this.y === point.y\n );\n },\n\n /**\n * Rotates the point around the specified pivot\n * From http://stackoverflow.com/questions/4465931/rotate-rectangle-around-a-point\n * @function\n * @param {Number} degress to rotate around the pivot.\n * @param {OpenSeadragon.Point} [pivot=(0,0)] Point around which to rotate.\n * Defaults to the origin.\n * @returns {OpenSeadragon.Point}. A new point representing the point rotated around the specified pivot\n */\n rotate: function (degrees, pivot) {\n pivot = pivot || new $.Point(0, 0);\n var cos;\n var sin;\n // Avoid float computations when possible\n if (degrees % 90 === 0) {\n var d = $.positiveModulo(degrees, 360);\n switch (d) {\n case 0:\n cos = 1;\n sin = 0;\n break;\n case 90:\n cos = 0;\n sin = 1;\n break;\n case 180:\n cos = -1;\n sin = 0;\n break;\n case 270:\n cos = 0;\n sin = -1;\n break;\n }\n } else {\n var angle = degrees * Math.PI / 180.0;\n cos = Math.cos(angle);\n sin = Math.sin(angle);\n }\n var x = cos * (this.x - pivot.x) - sin * (this.y - pivot.y) + pivot.x;\n var y = sin * (this.x - pivot.x) + cos * (this.y - pivot.y) + pivot.y;\n return new $.Point(x, y);\n },\n\n /**\n * Convert this point to a string in the format (x,y) where x and y are\n * rounded to the nearest integer.\n * @function\n * @returns {String} A string representation of this point.\n */\n toString: function() {\n return \"(\" + (Math.round(this.x * 100) / 100) + \",\" + (Math.round(this.y * 100) / 100) + \")\";\n }\n};\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - TileSource\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n\n/**\n * @class TileSource\n * @classdesc The TileSource contains the most basic implementation required to create a\n * smooth transition between layers in an image pyramid. It has only a single key\n * interface that must be implemented to complete its key functionality:\n * 'getTileUrl'. It also has several optional interfaces that can be\n * implemented if a new TileSource wishes to support configuration via a simple\n * object or array ('configure') and if the tile source supports or requires\n * configuration via retrieval of a document on the network ala AJAX or JSONP,\n * ('getImageInfo').\n *
      \n * By default the image pyramid is split into N layers where the image's longest\n * side in M (in pixels), where N is the smallest integer which satisfies\n * 2^(N+1) >= M.\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.EventSource\n * @param {Object} options\n * You can either specify a URL, or literally define the TileSource (by specifying\n * width, height, tileSize, tileOverlap, minLevel, and maxLevel). For the former,\n * the extending class is expected to implement 'getImageInfo' and 'configure'.\n * For the latter, the construction is assumed to occur through\n * the extending classes implementation of 'configure'.\n * @param {String} [options.url]\n * The URL for the data necessary for this TileSource.\n * @param {String} [options.referenceStripThumbnailUrl]\n * The URL for a thumbnail image to be used by the reference strip\n * @param {Function} [options.success]\n * A function to be called upon successful creation.\n * @param {Boolean} [options.ajaxWithCredentials]\n * If this TileSource needs to make an AJAX call, this specifies whether to set\n * the XHR's withCredentials (for accessing secure data).\n * @param {Object} [options.ajaxHeaders]\n * A set of headers to include in AJAX requests.\n * @param {Number} [options.width]\n * Width of the source image at max resolution in pixels.\n * @param {Number} [options.height]\n * Height of the source image at max resolution in pixels.\n * @param {Number} [options.tileSize]\n * The size of the tiles to assumed to make up each pyramid layer in pixels.\n * Tile size determines the point at which the image pyramid must be\n * divided into a matrix of smaller images.\n * Use options.tileWidth and options.tileHeight to support non-square tiles.\n * @param {Number} [options.tileWidth]\n * The width of the tiles to assumed to make up each pyramid layer in pixels.\n * @param {Number} [options.tileHeight]\n * The height of the tiles to assumed to make up each pyramid layer in pixels.\n * @param {Number} [options.tileOverlap]\n * The number of pixels each tile is expected to overlap touching tiles.\n * @param {Number} [options.minLevel]\n * The minimum level to attempt to load.\n * @param {Number} [options.maxLevel]\n * The maximum level to attempt to load.\n */\n$.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLevel ) {\n var _this = this;\n\n var args = arguments,\n options,\n i;\n\n if( $.isPlainObject( width ) ){\n options = width;\n }else{\n options = {\n width: args[0],\n height: args[1],\n tileSize: args[2],\n tileOverlap: args[3],\n minLevel: args[4],\n maxLevel: args[5]\n };\n }\n\n //Tile sources supply some events, namely 'ready' when they must be configured\n //by asynchronously fetching their configuration data.\n $.EventSource.call( this );\n\n //we allow options to override anything we dont treat as\n //required via idiomatic options or which is functionally\n //set depending on the state of the readiness of this tile\n //source\n $.extend( true, this, options );\n\n if (!this.success) {\n //Any functions that are passed as arguments are bound to the ready callback\n for ( i = 0; i < arguments.length; i++ ) {\n if ( $.isFunction( arguments[ i ] ) ) {\n this.success = arguments[ i ];\n //only one callback per constructor\n break;\n }\n }\n }\n\n if (this.success) {\n this.addHandler( 'ready', function ( event ) {\n _this.success( event );\n } );\n }\n\n /**\n * Ratio of width to height\n * @member {Number} aspectRatio\n * @memberof OpenSeadragon.TileSource#\n */\n /**\n * Vector storing x and y dimensions ( width and height respectively ).\n * @member {OpenSeadragon.Point} dimensions\n * @memberof OpenSeadragon.TileSource#\n */\n /**\n * The overlap in pixels each tile shares with its adjacent neighbors.\n * @member {Number} tileOverlap\n * @memberof OpenSeadragon.TileSource#\n */\n /**\n * The minimum pyramid level this tile source supports or should attempt to load.\n * @member {Number} minLevel\n * @memberof OpenSeadragon.TileSource#\n */\n /**\n * The maximum pyramid level this tile source supports or should attempt to load.\n * @member {Number} maxLevel\n * @memberof OpenSeadragon.TileSource#\n */\n /**\n *\n * @member {Boolean} ready\n * @memberof OpenSeadragon.TileSource#\n */\n\n if( 'string' == $.type( arguments[ 0 ] ) ){\n this.url = arguments[0];\n }\n\n if (this.url) {\n //in case the getImageInfo method is overriden and/or implies an\n //async mechanism set some safe defaults first\n this.aspectRatio = 1;\n this.dimensions = new $.Point( 10, 10 );\n this._tileWidth = 0;\n this._tileHeight = 0;\n this.tileOverlap = 0;\n this.minLevel = 0;\n this.maxLevel = 0;\n this.ready = false;\n //configuration via url implies the extending class\n //implements and 'configure'\n this.getImageInfo( this.url );\n\n } else {\n\n //explicit configuration via positional args in constructor\n //or the more idiomatic 'options' object\n this.ready = true;\n this.aspectRatio = (options.width && options.height) ?\n (options.width / options.height) : 1;\n this.dimensions = new $.Point( options.width, options.height );\n\n if ( this.tileSize ){\n this._tileWidth = this._tileHeight = this.tileSize;\n delete this.tileSize;\n } else {\n if( this.tileWidth ){\n // We were passed tileWidth in options, but we want to rename it\n // with a leading underscore to make clear that it is not safe to directly modify it\n this._tileWidth = this.tileWidth;\n delete this.tileWidth;\n } else {\n this._tileWidth = 0;\n }\n\n if( this.tileHeight ){\n // See note above about renaming this.tileWidth\n this._tileHeight = this.tileHeight;\n delete this.tileHeight;\n } else {\n this._tileHeight = 0;\n }\n }\n\n this.tileOverlap = options.tileOverlap ? options.tileOverlap : 0;\n this.minLevel = options.minLevel ? options.minLevel : 0;\n this.maxLevel = ( undefined !== options.maxLevel && null !== options.maxLevel ) ?\n options.maxLevel : (\n ( options.width && options.height ) ? Math.ceil(\n Math.log( Math.max( options.width, options.height ) ) /\n Math.log( 2 )\n ) : 0\n );\n if( this.success && $.isFunction( this.success ) ){\n this.success( this );\n }\n }\n\n\n};\n\n/** @lends OpenSeadragon.TileSource.prototype */\n$.TileSource.prototype = {\n\n getTileSize: function( level ) {\n $.console.error(\n \"[TileSource.getTileSize] is deprecated.\" +\n \"Use TileSource.getTileWidth() and TileSource.getTileHeight() instead\"\n );\n return this._tileWidth;\n },\n\n /**\n * Return the tileWidth for a given level.\n * Subclasses should override this if tileWidth can be different at different levels\n * such as in IIIFTileSource. Code should use this function rather than reading\n * from ._tileWidth directly.\n * @function\n * @param {Number} level\n */\n getTileWidth: function( level ) {\n if (!this._tileWidth) {\n return this.getTileSize(level);\n }\n return this._tileWidth;\n },\n\n /**\n * Return the tileHeight for a given level.\n * Subclasses should override this if tileHeight can be different at different levels\n * such as in IIIFTileSource. Code should use this function rather than reading\n * from ._tileHeight directly.\n * @function\n * @param {Number} level\n */\n getTileHeight: function( level ) {\n if (!this._tileHeight) {\n return this.getTileSize(level);\n }\n return this._tileHeight;\n },\n\n /**\n * @function\n * @param {Number} level\n */\n getLevelScale: function( level ) {\n\n // see https://github.com/openseadragon/openseadragon/issues/22\n // we use the tilesources implementation of getLevelScale to generate\n // a memoized re-implementation\n var levelScaleCache = {},\n i;\n for( i = 0; i <= this.maxLevel; i++ ){\n levelScaleCache[ i ] = 1 / Math.pow(2, this.maxLevel - i);\n }\n this.getLevelScale = function( _level ){\n return levelScaleCache[ _level ];\n };\n return this.getLevelScale( level );\n },\n\n /**\n * @function\n * @param {Number} level\n */\n getNumTiles: function( level ) {\n var scale = this.getLevelScale( level ),\n x = Math.ceil( scale * this.dimensions.x / this.getTileWidth(level) ),\n y = Math.ceil( scale * this.dimensions.y / this.getTileHeight(level) );\n\n return new $.Point( x, y );\n },\n\n /**\n * @function\n * @param {Number} level\n */\n getPixelRatio: function( level ) {\n var imageSizeScaled = this.dimensions.times( this.getLevelScale( level ) ),\n rx = 1.0 / imageSizeScaled.x,\n ry = 1.0 / imageSizeScaled.y;\n\n return new $.Point(rx, ry);\n },\n\n\n /**\n * @function\n * @returns {Number} The highest level in this tile source that can be contained in a single tile.\n */\n getClosestLevel: function() {\n var i,\n tiles;\n\n for (i = this.minLevel + 1; i <= this.maxLevel; i++){\n tiles = this.getNumTiles(i);\n if (tiles.x > 1 || tiles.y > 1) {\n break;\n }\n }\n\n return i - 1;\n },\n\n /**\n * @function\n * @param {Number} level\n * @param {OpenSeadragon.Point} point\n */\n getTileAtPoint: function(level, point) {\n var validPoint = point.x >= 0 && point.x <= 1 &&\n point.y >= 0 && point.y <= 1 / this.aspectRatio;\n $.console.assert(validPoint, \"[TileSource.getTileAtPoint] must be called with a valid point.\");\n\n var widthScaled = this.dimensions.x * this.getLevelScale(level);\n var pixelX = point.x * widthScaled;\n var pixelY = point.y * widthScaled;\n\n var x = Math.floor(pixelX / this.getTileWidth(level));\n var y = Math.floor(pixelY / this.getTileHeight(level));\n\n // When point.x == 1 or point.y == 1 / this.aspectRatio we want to\n // return the last tile of the row/column\n if (point.x >= 1) {\n x = this.getNumTiles(level).x - 1;\n }\n var EPSILON = 1e-16;\n if (point.y >= 1 / this.aspectRatio - EPSILON) {\n y = this.getNumTiles(level).y - 1;\n }\n\n return new $.Point(x, y);\n },\n\n /**\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n */\n getTileBounds: function( level, x, y ) {\n var dimensionsScaled = this.dimensions.times( this.getLevelScale( level ) ),\n tileWidth = this.getTileWidth(level),\n tileHeight = this.getTileHeight(level),\n px = ( x === 0 ) ? 0 : tileWidth * x - this.tileOverlap,\n py = ( y === 0 ) ? 0 : tileHeight * y - this.tileOverlap,\n sx = tileWidth + ( x === 0 ? 1 : 2 ) * this.tileOverlap,\n sy = tileHeight + ( y === 0 ? 1 : 2 ) * this.tileOverlap,\n scale = 1.0 / dimensionsScaled.x;\n\n sx = Math.min( sx, dimensionsScaled.x - px );\n sy = Math.min( sy, dimensionsScaled.y - py );\n\n return new $.Rect( px * scale, py * scale, sx * scale, sy * scale );\n },\n\n\n /**\n * Responsible for retrieving, and caching the\n * image metadata pertinent to this TileSources implementation.\n * @function\n * @param {String} url\n * @throws {Error}\n */\n getImageInfo: function( url ) {\n var _this = this,\n callbackName,\n callback,\n readySource,\n options,\n urlParts,\n filename,\n lastDot;\n\n\n if( url ) {\n urlParts = url.split( '/' );\n filename = urlParts[ urlParts.length - 1 ];\n lastDot = filename.lastIndexOf( '.' );\n if ( lastDot > -1 ) {\n urlParts[ urlParts.length - 1 ] = filename.slice( 0, lastDot );\n }\n }\n\n callback = function( data ){\n if( typeof(data) === \"string\" ) {\n data = $.parseXml( data );\n }\n var $TileSource = $.TileSource.determineType( _this, data, url );\n if ( !$TileSource ) {\n /**\n * Raised when an error occurs loading a TileSource.\n *\n * @event open-failed\n * @memberof OpenSeadragon.TileSource\n * @type {object}\n * @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event.\n * @property {String} message\n * @property {String} source\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( 'open-failed', { message: \"Unable to load TileSource\", source: url } );\n return;\n }\n\n options = $TileSource.prototype.configure.apply( _this, [ data, url ]);\n if (options.ajaxWithCredentials === undefined) {\n options.ajaxWithCredentials = _this.ajaxWithCredentials;\n }\n\n readySource = new $TileSource( options );\n _this.ready = true;\n /**\n * Raised when a TileSource is opened and initialized.\n *\n * @event ready\n * @memberof OpenSeadragon.TileSource\n * @type {object}\n * @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event.\n * @property {Object} tileSource\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( 'ready', { tileSource: readySource } );\n };\n\n if( url.match(/\\.js$/) ){\n //TODO: Its not very flexible to require tile sources to end jsonp\n // request for info with a url that ends with '.js' but for\n // now it's the only way I see to distinguish uniformly.\n callbackName = url.split('/').pop().replace('.js', '');\n $.jsonp({\n url: url,\n async: false,\n callbackName: callbackName,\n callback: callback\n });\n } else {\n // request info via xhr asynchronously.\n $.makeAjaxRequest( {\n url: url,\n withCredentials: this.ajaxWithCredentials,\n headers: this.ajaxHeaders,\n success: function( xhr ) {\n var data = processResponse( xhr );\n callback( data );\n },\n error: function ( xhr, exc ) {\n var msg;\n\n /*\n IE < 10 will block XHR requests to different origins. Any property access on the request\n object will raise an exception which we'll attempt to handle by formatting the original\n exception rather than the second one raised when we try to access xhr.status\n */\n try {\n msg = \"HTTP \" + xhr.status + \" attempting to load TileSource\";\n } catch ( e ) {\n var formattedExc;\n if ( typeof( exc ) == \"undefined\" || !exc.toString ) {\n formattedExc = \"Unknown error\";\n } else {\n formattedExc = exc.toString();\n }\n\n msg = formattedExc + \" attempting to load TileSource\";\n }\n\n /***\n * Raised when an error occurs loading a TileSource.\n *\n * @event open-failed\n * @memberof OpenSeadragon.TileSource\n * @type {object}\n * @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event.\n * @property {String} message\n * @property {String} source\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( 'open-failed', {\n message: msg,\n source: url\n });\n }\n });\n }\n\n },\n\n /**\n * Responsible determining if a the particular TileSource supports the\n * data format ( and allowed to apply logic against the url the data was\n * loaded from, if any ). Overriding implementations are expected to do\n * something smart with data and / or url to determine support. Also\n * understand that iteration order of TileSources is not guarunteed so\n * please make sure your data or url is expressive enough to ensure a simple\n * and sufficient mechanisim for clear determination.\n * @function\n * @param {String|Object|Array|Document} data\n * @param {String} url - the url the data was loaded\n * from if any.\n * @return {Boolean}\n */\n supports: function( data, url ) {\n return false;\n },\n\n /**\n * Responsible for parsing and configuring the\n * image metadata pertinent to this TileSources implementation.\n * This method is not implemented by this class other than to throw an Error\n * announcing you have to implement it. Because of the variety of tile\n * server technologies, and various specifications for building image\n * pyramids, this method is here to allow easy integration.\n * @function\n * @param {String|Object|Array|Document} data\n * @param {String} url - the url the data was loaded\n * from if any.\n * @return {Object} options - A dictionary of keyword arguments sufficient\n * to configure this tile sources constructor.\n * @throws {Error}\n */\n configure: function( data, url ) {\n throw new Error( \"Method not implemented.\" );\n },\n\n /**\n * Responsible for retrieving the url which will return an image for the\n * region specified by the given x, y, and level components.\n * This method is not implemented by this class other than to throw an Error\n * announcing you have to implement it. Because of the variety of tile\n * server technologies, and various specifications for building image\n * pyramids, this method is here to allow easy integration.\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n * @throws {Error}\n */\n getTileUrl: function( level, x, y ) {\n throw new Error( \"Method not implemented.\" );\n },\n\n /**\n * Responsible for retrieving the headers which will be attached to the image request for the\n * region specified by the given x, y, and level components.\n * This option is only relevant if {@link OpenSeadragon.Options}.loadTilesWithAjax is set to true.\n * The headers returned here will override headers specified at the Viewer or TiledImage level.\n * Specifying a falsy value for a header will clear its existing value set at the Viewer or\n * TiledImage level (if any).\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n * @returns {Object}\n */\n getTileAjaxHeaders: function( level, x, y ) {\n return {};\n },\n\n /**\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n */\n tileExists: function( level, x, y ) {\n var numTiles = this.getNumTiles( level );\n return level >= this.minLevel &&\n level <= this.maxLevel &&\n x >= 0 &&\n y >= 0 &&\n x < numTiles.x &&\n y < numTiles.y;\n }\n};\n\n\n$.extend( true, $.TileSource.prototype, $.EventSource.prototype );\n\n\n/**\n * Decides whether to try to process the response as xml, json, or hand back\n * the text\n * @private\n * @inner\n * @function\n * @param {XMLHttpRequest} xhr - the completed network request\n */\nfunction processResponse( xhr ){\n var responseText = xhr.responseText,\n status = xhr.status,\n statusText,\n data;\n\n if ( !xhr ) {\n throw new Error( $.getString( \"Errors.Security\" ) );\n } else if ( xhr.status !== 200 && xhr.status !== 0 ) {\n status = xhr.status;\n statusText = ( status == 404 ) ?\n \"Not Found\" :\n xhr.statusText;\n throw new Error( $.getString( \"Errors.Status\", status, statusText ) );\n }\n\n if( responseText.match(/\\s*<.*/) ){\n try{\n data = ( xhr.responseXML && xhr.responseXML.documentElement ) ?\n xhr.responseXML :\n $.parseXml( responseText );\n } catch (e){\n data = xhr.responseText;\n }\n }else if( responseText.match(/\\s*[\\{\\[].*/) ){\n try{\n data = $.parseJSON(responseText);\n } catch(e){\n data = responseText;\n }\n }else{\n data = responseText;\n }\n return data;\n}\n\n\n/**\n * Determines the TileSource Implementation by introspection of OpenSeadragon\n * namespace, calling each TileSource implementation of 'isType'\n * @private\n * @inner\n * @function\n * @param {Object|Array|Document} data - the tile source configuration object\n * @param {String} url - the url where the tile source configuration object was\n * loaded from, if any.\n */\n$.TileSource.determineType = function( tileSource, data, url ){\n var property;\n for( property in OpenSeadragon ){\n if( property.match(/.+TileSource$/) &&\n $.isFunction( OpenSeadragon[ property ] ) &&\n $.isFunction( OpenSeadragon[ property ].prototype.supports ) &&\n OpenSeadragon[ property ].prototype.supports.call( tileSource, data, url )\n ){\n return OpenSeadragon[ property ];\n }\n }\n\n $.console.error( \"No TileSource was able to open %s %s\", url, data );\n};\n\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - DziTileSource\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class DziTileSource\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.TileSource\n * @param {Number|Object} width - the pixel width of the image or the idiomatic\n * options object which is used instead of positional arguments.\n * @param {Number} height\n * @param {Number} tileSize\n * @param {Number} tileOverlap\n * @param {String} tilesUrl\n * @param {String} fileFormat\n * @param {OpenSeadragon.DisplayRect[]} displayRects\n * @property {String} tilesUrl\n * @property {String} fileFormat\n * @property {OpenSeadragon.DisplayRect[]} displayRects\n */\n$.DziTileSource = function( width, height, tileSize, tileOverlap, tilesUrl, fileFormat, displayRects, minLevel, maxLevel ) {\n var i,\n rect,\n level,\n options;\n\n if( $.isPlainObject( width ) ){\n options = width;\n }else{\n options = {\n width: arguments[ 0 ],\n height: arguments[ 1 ],\n tileSize: arguments[ 2 ],\n tileOverlap: arguments[ 3 ],\n tilesUrl: arguments[ 4 ],\n fileFormat: arguments[ 5 ],\n displayRects: arguments[ 6 ],\n minLevel: arguments[ 7 ],\n maxLevel: arguments[ 8 ]\n };\n }\n\n this._levelRects = {};\n this.tilesUrl = options.tilesUrl;\n this.fileFormat = options.fileFormat;\n this.displayRects = options.displayRects;\n\n if ( this.displayRects ) {\n for ( i = this.displayRects.length - 1; i >= 0; i-- ) {\n rect = this.displayRects[ i ];\n for ( level = rect.minLevel; level <= rect.maxLevel; level++ ) {\n if ( !this._levelRects[ level ] ) {\n this._levelRects[ level ] = [];\n }\n this._levelRects[ level ].push( rect );\n }\n }\n }\n\n $.TileSource.apply( this, [ options ] );\n\n};\n\n$.extend( $.DziTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.DziTileSource.prototype */{\n\n\n /**\n * Determine if the data and/or url imply the image service is supported by\n * this tile source.\n * @function\n * @param {Object|Array} data\n * @param {String} optional - url\n */\n supports: function( data, url ){\n var ns;\n if ( data.Image ) {\n ns = data.Image.xmlns;\n } else if ( data.documentElement) {\n if (\"Image\" == data.documentElement.localName || \"Image\" == data.documentElement.tagName) {\n ns = data.documentElement.namespaceURI;\n }\n }\n\n ns = (ns || '').toLowerCase();\n\n return (ns.indexOf('schemas.microsoft.com/deepzoom/2008') !== -1 ||\n ns.indexOf('schemas.microsoft.com/deepzoom/2009') !== -1);\n },\n\n /**\n *\n * @function\n * @param {Object|XMLDocument} data - the raw configuration\n * @param {String} url - the url the data was retreived from if any.\n * @return {Object} options - A dictionary of keyword arguments sufficient\n * to configure this tile sources constructor.\n */\n configure: function( data, url ){\n\n var options;\n\n if( !$.isPlainObject(data) ){\n\n options = configureFromXML( this, data );\n\n }else{\n\n options = configureFromObject( this, data );\n }\n\n if (url && !options.tilesUrl) {\n options.tilesUrl = url.replace(\n /([^\\/]+?)(\\.(dzi|xml|js)?(\\?[^\\/]*)?)?\\/?$/, '$1_files/');\n\n if (url.search(/\\.(dzi|xml|js)\\?/) != -1) {\n options.queryParams = url.match(/\\?.*/);\n }else{\n options.queryParams = '';\n }\n }\n\n return options;\n },\n\n\n /**\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n */\n getTileUrl: function( level, x, y ) {\n return [ this.tilesUrl, level, '/', x, '_', y, '.', this.fileFormat, this.queryParams ].join( '' );\n },\n\n\n /**\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n */\n tileExists: function( level, x, y ) {\n var rects = this._levelRects[ level ],\n rect,\n scale,\n xMin,\n yMin,\n xMax,\n yMax,\n i;\n\n if ( !rects || !rects.length ) {\n return true;\n }\n\n for ( i = rects.length - 1; i >= 0; i-- ) {\n rect = rects[ i ];\n\n if ( level < rect.minLevel || level > rect.maxLevel ) {\n continue;\n }\n\n scale = this.getLevelScale( level );\n xMin = rect.x * scale;\n yMin = rect.y * scale;\n xMax = xMin + rect.width * scale;\n yMax = yMin + rect.height * scale;\n\n xMin = Math.floor( xMin / this._tileWidth );\n yMin = Math.floor( yMin / this._tileWidth ); // DZI tiles are square, so we just use _tileWidth\n xMax = Math.ceil( xMax / this._tileWidth );\n yMax = Math.ceil( yMax / this._tileWidth );\n\n if ( xMin <= x && x < xMax && yMin <= y && y < yMax ) {\n return true;\n }\n }\n\n return false;\n }\n});\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction configureFromXML( tileSource, xmlDoc ){\n\n if ( !xmlDoc || !xmlDoc.documentElement ) {\n throw new Error( $.getString( \"Errors.Xml\" ) );\n }\n\n var root = xmlDoc.documentElement,\n rootName = root.localName || root.tagName,\n ns = xmlDoc.documentElement.namespaceURI,\n configuration = null,\n displayRects = [],\n dispRectNodes,\n dispRectNode,\n rectNode,\n sizeNode,\n i;\n\n if ( rootName == \"Image\" ) {\n\n try {\n sizeNode = root.getElementsByTagName(\"Size\" )[ 0 ];\n if (sizeNode === undefined) {\n sizeNode = root.getElementsByTagNameNS(ns, \"Size\" )[ 0 ];\n }\n\n configuration = {\n Image: {\n xmlns: \"http://schemas.microsoft.com/deepzoom/2008\",\n Url: root.getAttribute( \"Url\" ),\n Format: root.getAttribute( \"Format\" ),\n DisplayRect: null,\n Overlap: parseInt( root.getAttribute( \"Overlap\" ), 10 ),\n TileSize: parseInt( root.getAttribute( \"TileSize\" ), 10 ),\n Size: {\n Height: parseInt( sizeNode.getAttribute( \"Height\" ), 10 ),\n Width: parseInt( sizeNode.getAttribute( \"Width\" ), 10 )\n }\n }\n };\n\n if ( !$.imageFormatSupported( configuration.Image.Format ) ) {\n throw new Error(\n $.getString( \"Errors.ImageFormat\", configuration.Image.Format.toUpperCase() )\n );\n }\n\n dispRectNodes = root.getElementsByTagName(\"DisplayRect\" );\n if (dispRectNodes === undefined) {\n dispRectNodes = root.getElementsByTagNameNS(ns, \"DisplayRect\" )[ 0 ];\n }\n\n for ( i = 0; i < dispRectNodes.length; i++ ) {\n dispRectNode = dispRectNodes[ i ];\n rectNode = dispRectNode.getElementsByTagName(\"Rect\" )[ 0 ];\n if (rectNode === undefined) {\n rectNode = dispRectNode.getElementsByTagNameNS(ns, \"Rect\" )[ 0 ];\n }\n\n displayRects.push({\n Rect: {\n X: parseInt( rectNode.getAttribute( \"X\" ), 10 ),\n Y: parseInt( rectNode.getAttribute( \"Y\" ), 10 ),\n Width: parseInt( rectNode.getAttribute( \"Width\" ), 10 ),\n Height: parseInt( rectNode.getAttribute( \"Height\" ), 10 ),\n MinLevel: parseInt( dispRectNode.getAttribute( \"MinLevel\" ), 10 ),\n MaxLevel: parseInt( dispRectNode.getAttribute( \"MaxLevel\" ), 10 )\n }\n });\n }\n\n if( displayRects.length ){\n configuration.Image.DisplayRect = displayRects;\n }\n\n return configureFromObject( tileSource, configuration );\n\n } catch ( e ) {\n throw (e instanceof Error) ?\n e :\n new Error( $.getString(\"Errors.Dzi\") );\n }\n } else if ( rootName == \"Collection\" ) {\n throw new Error( $.getString( \"Errors.Dzc\" ) );\n } else if ( rootName == \"Error\" ) {\n var messageNode = root.getElementsByTagName(\"Message\")[0];\n var message = messageNode.firstChild.nodeValue;\n throw new Error(message);\n }\n\n throw new Error( $.getString( \"Errors.Dzi\" ) );\n}\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction configureFromObject( tileSource, configuration ){\n var imageData = configuration.Image,\n tilesUrl = imageData.Url,\n fileFormat = imageData.Format,\n sizeData = imageData.Size,\n dispRectData = imageData.DisplayRect || [],\n width = parseInt( sizeData.Width, 10 ),\n height = parseInt( sizeData.Height, 10 ),\n tileSize = parseInt( imageData.TileSize, 10 ),\n tileOverlap = parseInt( imageData.Overlap, 10 ),\n displayRects = [],\n rectData,\n i;\n\n //TODO: need to figure out out to better handle image format compatibility\n // which actually includes additional file formats like xml and pdf\n // and plain text for various tilesource implementations to avoid low\n // level errors.\n //\n // For now, just don't perform the check.\n //\n /*if ( !imageFormatSupported( fileFormat ) ) {\n throw new Error(\n $.getString( \"Errors.ImageFormat\", fileFormat.toUpperCase() )\n );\n }*/\n\n for ( i = 0; i < dispRectData.length; i++ ) {\n rectData = dispRectData[ i ].Rect;\n\n displayRects.push( new $.DisplayRect(\n parseInt( rectData.X, 10 ),\n parseInt( rectData.Y, 10 ),\n parseInt( rectData.Width, 10 ),\n parseInt( rectData.Height, 10 ),\n parseInt( rectData.MinLevel, 10 ),\n parseInt( rectData.MaxLevel, 10 )\n ));\n }\n\n return $.extend(true, {\n width: width, /* width *required */\n height: height, /* height *required */\n tileSize: tileSize, /* tileSize *required */\n tileOverlap: tileOverlap, /* tileOverlap *required */\n minLevel: null, /* minLevel */\n maxLevel: null, /* maxLevel */\n tilesUrl: tilesUrl, /* tilesUrl */\n fileFormat: fileFormat, /* fileFormat */\n displayRects: displayRects /* displayRects */\n }, configuration );\n\n}\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - IIIFTileSource\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class IIIFTileSource\n * @classdesc A client implementation of the International Image Interoperability Framework\n * Format: Image API 1.0 - 2.1\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.TileSource\n * @see http://iiif.io/api/image/\n */\n$.IIIFTileSource = function( options ){\n\n /* eslint-disable camelcase */\n\n $.extend( true, this, options );\n\n if ( !( this.height && this.width && this['@id'] ) ) {\n throw new Error( 'IIIF required parameters not provided.' );\n }\n\n options.tileSizePerScaleFactor = {};\n\n // N.B. 2.0 renamed scale_factors to scaleFactors\n if ( this.tile_width && this.tile_height ) {\n options.tileWidth = this.tile_width;\n options.tileHeight = this.tile_height;\n } else if ( this.tile_width ) {\n options.tileSize = this.tile_width;\n } else if ( this.tile_height ) {\n options.tileSize = this.tile_height;\n } else if ( this.tiles ) {\n // Version 2.0 forwards\n if ( this.tiles.length == 1 ) {\n options.tileWidth = this.tiles[0].width;\n // Use height if provided, otherwise assume square tiles and use width.\n options.tileHeight = this.tiles[0].height || this.tiles[0].width;\n this.scale_factors = this.tiles[0].scaleFactors;\n } else {\n // Multiple tile sizes at different levels\n this.scale_factors = [];\n for (var t = 0; t < this.tiles.length; t++ ) {\n for (var sf = 0; sf < this.tiles[t].scaleFactors.length; sf++) {\n var scaleFactor = this.tiles[t].scaleFactors[sf];\n this.scale_factors.push(scaleFactor);\n options.tileSizePerScaleFactor[scaleFactor] = {\n width: this.tiles[t].width,\n height: this.tiles[t].height || this.tiles[t].width\n };\n }\n }\n }\n } else if ( canBeTiled(options.profile) ) {\n // use the largest of tileOptions that is smaller than the short dimension\n var shortDim = Math.min( this.height, this.width ),\n tileOptions = [256, 512, 1024],\n smallerTiles = [];\n\n for ( var c = 0; c < tileOptions.length; c++ ) {\n if ( tileOptions[c] <= shortDim ) {\n smallerTiles.push( tileOptions[c] );\n }\n }\n\n if ( smallerTiles.length > 0 ) {\n options.tileSize = Math.max.apply( null, smallerTiles );\n } else {\n // If we're smaller than 256, just use the short side.\n options.tileSize = shortDim;\n }\n } else if (this.sizes && this.sizes.length > 0) {\n // This info.json can't be tiled, but we can still construct a legacy pyramid from the sizes array.\n // In this mode, IIIFTileSource will call functions from the abstract baseTileSource or the\n // LegacyTileSource instead of performing IIIF tiling.\n this.emulateLegacyImagePyramid = true;\n\n options.levels = constructLevels( this );\n // use the largest available size to define tiles\n $.extend( true, options, {\n width: options.levels[ options.levels.length - 1 ].width,\n height: options.levels[ options.levels.length - 1 ].height,\n tileSize: Math.max( options.height, options.width ),\n tileOverlap: 0,\n minLevel: 0,\n maxLevel: options.levels.length - 1\n });\n this.levels = options.levels;\n } else {\n $.console.error(\"Nothing in the info.json to construct image pyramids from\");\n }\n\n if (!options.maxLevel && !this.emulateLegacyImagePyramid) {\n if (!this.scale_factors) {\n options.maxLevel = Number(Math.ceil(Math.log(Math.max(this.width, this.height), 2)));\n } else {\n options.maxLevel = Math.floor(Math.pow(Math.max.apply(null, this.scale_factors), 0.5));\n }\n }\n\n $.TileSource.apply( this, [ options ] );\n};\n\n$.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.IIIFTileSource.prototype */{\n /**\n * Determine if the data and/or url imply the image service is supported by\n * this tile source.\n * @function\n * @param {Object|Array} data\n * @param {String} optional - url\n */\n\n supports: function( data, url ) {\n // Version 2.0 and forwards\n if (data.protocol && data.protocol == 'http://iiif.io/api/image') {\n return true;\n // Version 1.1\n } else if ( data['@context'] && (\n data['@context'] == \"http://library.stanford.edu/iiif/image-api/1.1/context.json\" ||\n data['@context'] == \"http://iiif.io/api/image/1/context.json\") ) {\n // N.B. the iiif.io context is wrong, but where the representation lives so likely to be used\n return true;\n\n // Version 1.0\n } else if ( data.profile &&\n data.profile.indexOf(\"http://library.stanford.edu/iiif/image-api/compliance.html\") === 0) {\n return true;\n } else if ( data.identifier && data.width && data.height ) {\n return true;\n } else if ( data.documentElement &&\n \"info\" == data.documentElement.tagName &&\n \"http://library.stanford.edu/iiif/image-api/ns/\" ==\n data.documentElement.namespaceURI) {\n return true;\n\n // Not IIIF\n } else {\n return false;\n }\n },\n\n /**\n *\n * @function\n * @param {Object} data - the raw configuration\n * @example IIIF 1.1 Info Looks like this\n * {\n * \"@context\" : \"http://library.stanford.edu/iiif/image-api/1.1/context.json\",\n * \"@id\" : \"http://iiif.example.com/prefix/1E34750D-38DB-4825-A38A-B60A345E591C\",\n * \"width\" : 6000,\n * \"height\" : 4000,\n * \"scale_factors\" : [ 1, 2, 4 ],\n * \"tile_width\" : 1024,\n * \"tile_height\" : 1024,\n * \"formats\" : [ \"jpg\", \"png\" ],\n * \"qualities\" : [ \"native\", \"grey\" ],\n * \"profile\" : \"http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0\"\n * }\n */\n configure: function( data, url ){\n // Try to deduce our version and fake it upwards if needed\n if ( !$.isPlainObject(data) ) {\n var options = configureFromXml10( data );\n options['@context'] = \"http://iiif.io/api/image/1.0/context.json\";\n options['@id'] = url.replace('/info.xml', '');\n return options;\n } else if ( !data['@context'] ) {\n data['@context'] = 'http://iiif.io/api/image/1.0/context.json';\n data['@id'] = url.replace('/info.json', '');\n return data;\n } else {\n return data;\n }\n },\n\n /**\n * Return the tileWidth for the given level.\n * @function\n * @param {Number} level\n */\n getTileWidth: function( level ) {\n\n if(this.emulateLegacyImagePyramid) {\n return $.TileSource.prototype.getTileWidth.call(this, level);\n }\n\n var scaleFactor = Math.pow(2, this.maxLevel - level);\n\n if (this.tileSizePerScaleFactor && this.tileSizePerScaleFactor[scaleFactor]) {\n return this.tileSizePerScaleFactor[scaleFactor].width;\n }\n return this._tileWidth;\n },\n\n /**\n * Return the tileHeight for the given level.\n * @function\n * @param {Number} level\n */\n getTileHeight: function( level ) {\n\n if(this.emulateLegacyImagePyramid) {\n return $.TileSource.prototype.getTileHeight.call(this, level);\n }\n\n var scaleFactor = Math.pow(2, this.maxLevel - level);\n\n if (this.tileSizePerScaleFactor && this.tileSizePerScaleFactor[scaleFactor]) {\n return this.tileSizePerScaleFactor[scaleFactor].height;\n }\n return this._tileHeight;\n },\n\n /**\n * @function\n * @param {Number} level\n */\n getLevelScale: function ( level ) {\n\n if(this.emulateLegacyImagePyramid) {\n var levelScale = NaN;\n if (this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel) {\n levelScale =\n this.levels[level].width /\n this.levels[this.maxLevel].width;\n }\n return levelScale;\n }\n\n return $.TileSource.prototype.getLevelScale.call(this, level);\n },\n\n /**\n * @function\n * @param {Number} level\n */\n getNumTiles: function( level ) {\n\n if(this.emulateLegacyImagePyramid) {\n var scale = this.getLevelScale(level);\n if (scale) {\n return new $.Point(1, 1);\n } else {\n return new $.Point(0, 0);\n }\n }\n\n return $.TileSource.prototype.getNumTiles.call(this, level);\n },\n\n\n /**\n * @function\n * @param {Number} level\n * @param {OpenSeadragon.Point} point\n */\n getTileAtPoint: function( level, point ) {\n\n if(this.emulateLegacyImagePyramid) {\n return new $.Point(0, 0);\n }\n\n return $.TileSource.prototype.getTileAtPoint.call(this, level, point);\n },\n\n\n /**\n * Responsible for retrieving the url which will return an image for the\n * region specified by the given x, y, and level components.\n * @function\n * @param {Number} level - z index\n * @param {Number} x\n * @param {Number} y\n * @throws {Error}\n */\n getTileUrl: function( level, x, y ){\n\n if(this.emulateLegacyImagePyramid) {\n var url = null;\n if ( this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel ) {\n url = this.levels[ level ].url;\n }\n return url;\n }\n\n //# constants\n var IIIF_ROTATION = '0',\n //## get the scale (level as a decimal)\n scale = Math.pow( 0.5, this.maxLevel - level ),\n\n //# image dimensions at this level\n levelWidth = Math.ceil( this.width * scale ),\n levelHeight = Math.ceil( this.height * scale ),\n\n //## iiif region\n tileWidth,\n tileHeight,\n iiifTileSizeWidth,\n iiifTileSizeHeight,\n iiifRegion,\n iiifTileX,\n iiifTileY,\n iiifTileW,\n iiifTileH,\n iiifSize,\n iiifQuality,\n uri;\n\n tileWidth = this.getTileWidth(level);\n tileHeight = this.getTileHeight(level);\n iiifTileSizeWidth = Math.ceil( tileWidth / scale );\n iiifTileSizeHeight = Math.ceil( tileHeight / scale );\n\n if ( this['@context'].indexOf('/1.0/context.json') > -1 ||\n this['@context'].indexOf('/1.1/context.json') > -1 ||\n this['@context'].indexOf('/1/context.json') > -1 ) {\n iiifQuality = \"native.jpg\";\n } else {\n iiifQuality = \"default.jpg\";\n }\n\n if ( levelWidth < tileWidth && levelHeight < tileHeight ){\n iiifSize = levelWidth + \",\";\n iiifRegion = 'full';\n } else {\n iiifTileX = x * iiifTileSizeWidth;\n iiifTileY = y * iiifTileSizeHeight;\n iiifTileW = Math.min( iiifTileSizeWidth, this.width - iiifTileX );\n iiifTileH = Math.min( iiifTileSizeHeight, this.height - iiifTileY );\n iiifSize = Math.ceil( iiifTileW * scale ) + \",\";\n iiifRegion = [ iiifTileX, iiifTileY, iiifTileW, iiifTileH ].join( ',' );\n }\n uri = [ this['@id'], iiifRegion, iiifSize, IIIF_ROTATION, iiifQuality ].join( '/' );\n\n return uri;\n }\n\n });\n\n /**\n * Determine whether arbitrary tile requests can be made against a service with the given profile\n * @function\n * @param {object} profile - IIIF profile object\n * @throws {Error}\n */\n function canBeTiled (profile ) {\n var level0Profiles = [\n \"http://library.stanford.edu/iiif/image-api/compliance.html#level0\",\n \"http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0\",\n \"http://iiif.io/api/image/2/level0.json\"\n ];\n var isLevel0 = (level0Profiles.indexOf(profile[0]) != -1);\n return !isLevel0 || (profile.indexOf(\"sizeByW\") != -1);\n }\n\n /**\n * Build the legacy pyramid URLs (one tile per level)\n * @function\n * @param {object} options - infoJson\n * @throws {Error}\n */\n function constructLevels(options) {\n var levels = [];\n for(var i = 0; i < options.sizes.length; i++) {\n levels.push({\n url: options['@id'] + '/full/' + options.sizes[i].width + ',/0/default.jpg',\n width: options.sizes[i].width,\n height: options.sizes[i].height\n });\n }\n return levels.sort(function(a, b) {\n return a.width - b.width;\n });\n }\n\n\n function configureFromXml10(xmlDoc) {\n //parse the xml\n if ( !xmlDoc || !xmlDoc.documentElement ) {\n throw new Error( $.getString( \"Errors.Xml\" ) );\n }\n\n var root = xmlDoc.documentElement,\n rootName = root.tagName,\n configuration = null;\n\n if ( rootName == \"info\" ) {\n try {\n configuration = {};\n parseXML10( root, configuration );\n return configuration;\n\n } catch ( e ) {\n throw (e instanceof Error) ?\n e :\n new Error( $.getString(\"Errors.IIIF\") );\n }\n }\n throw new Error( $.getString( \"Errors.IIIF\" ) );\n }\n\n function parseXML10( node, configuration, property ) {\n var i,\n value;\n if ( node.nodeType == 3 && property ) {//text node\n value = node.nodeValue.trim();\n if( value.match(/^\\d*$/)){\n value = Number( value );\n }\n if( !configuration[ property ] ){\n configuration[ property ] = value;\n }else{\n if( !$.isArray( configuration[ property ] ) ){\n configuration[ property ] = [ configuration[ property ] ];\n }\n configuration[ property ].push( value );\n }\n } else if( node.nodeType == 1 ){\n for( i = 0; i < node.childNodes.length; i++ ){\n parseXML10( node.childNodes[ i ], configuration, node.nodeName );\n }\n }\n }\n\n\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - OsmTileSource\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/*\n * Derived from the OSM tile source in Rainer Simon's seajax-utils project\n * . Rainer Simon has contributed\n * the included code to the OpenSeadragon project under the New BSD license;\n * see .\n */\n\n\n(function( $ ){\n\n/**\n * @class OsmTileSource\n * @classdesc A tilesource implementation for OpenStreetMap.

      \n *\n * Note 1. Zoomlevels. Deep Zoom and OSM define zoom levels differently. In Deep\n * Zoom, level 0 equals an image of 1x1 pixels. In OSM, level 0 equals an image of\n * 256x256 levels (see http://gasi.ch/blog/inside-deep-zoom-2). I.e. there is a\n * difference of log2(256)=8 levels.

      \n *\n * Note 2. Image dimension. According to the OSM Wiki\n * (http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Zoom_levels)\n * the highest Mapnik zoom level has 256.144x256.144 tiles, with a 256x256\n * pixel size. I.e. the Deep Zoom image dimension is 65.572.864x65.572.864\n * pixels.\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.TileSource\n * @param {Number|Object} width - the pixel width of the image or the idiomatic\n * options object which is used instead of positional arguments.\n * @param {Number} height\n * @param {Number} tileSize\n * @param {Number} tileOverlap\n * @param {String} tilesUrl\n */\n$.OsmTileSource = function( width, height, tileSize, tileOverlap, tilesUrl ) {\n var options;\n\n if( $.isPlainObject( width ) ){\n options = width;\n }else{\n options = {\n width: arguments[0],\n height: arguments[1],\n tileSize: arguments[2],\n tileOverlap: arguments[3],\n tilesUrl: arguments[4]\n };\n }\n //apply default setting for standard public OpenStreatMaps service\n //but allow them to be specified so fliks can host there own instance\n //or apply against other services supportting the same standard\n if( !options.width || !options.height ){\n options.width = 65572864;\n options.height = 65572864;\n }\n if( !options.tileSize ){\n options.tileSize = 256;\n options.tileOverlap = 0;\n }\n if( !options.tilesUrl ){\n options.tilesUrl = \"http://tile.openstreetmap.org/\";\n }\n options.minLevel = 8;\n\n $.TileSource.apply( this, [ options ] );\n\n};\n\n$.extend( $.OsmTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.OsmTileSource.prototype */{\n\n\n /**\n * Determine if the data and/or url imply the image service is supported by\n * this tile source.\n * @function\n * @param {Object|Array} data\n * @param {String} optional - url\n */\n supports: function( data, url ){\n return (\n data.type &&\n \"openstreetmaps\" == data.type\n );\n },\n\n /**\n *\n * @function\n * @param {Object} data - the raw configuration\n * @param {String} url - the url the data was retreived from if any.\n * @return {Object} options - A dictionary of keyword arguments sufficient\n * to configure this tile sources constructor.\n */\n configure: function( data, url ){\n return data;\n },\n\n\n /**\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n */\n getTileUrl: function( level, x, y ) {\n return this.tilesUrl + (level - 8) + \"/\" + x + \"/\" + y + \".png\";\n }\n});\n\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - TmsTileSource\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/*\n * Derived from the TMS tile source in Rainer Simon's seajax-utils project\n * . Rainer Simon has contributed\n * the included code to the OpenSeadragon project under the New BSD license;\n * see .\n */\n\n\n(function( $ ){\n\n/**\n * @class TmsTileSource\n * @classdesc A tilesource implementation for Tiled Map Services (TMS).\n * TMS tile scheme ( [ as supported by OpenLayers ] is described here\n * ( http://openlayers.org/dev/examples/tms.html ).\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.TileSource\n * @param {Number|Object} width - the pixel width of the image or the idiomatic\n * options object which is used instead of positional arguments.\n * @param {Number} height\n * @param {Number} tileSize\n * @param {Number} tileOverlap\n * @param {String} tilesUrl\n */\n$.TmsTileSource = function( width, height, tileSize, tileOverlap, tilesUrl ) {\n var options;\n\n if( $.isPlainObject( width ) ){\n options = width;\n }else{\n options = {\n width: arguments[0],\n height: arguments[1],\n tileSize: arguments[2],\n tileOverlap: arguments[3],\n tilesUrl: arguments[4]\n };\n }\n // TMS has integer multiples of 256 for width/height and adds buffer\n // if necessary -> account for this!\n var bufferedWidth = Math.ceil(options.width / 256) * 256,\n bufferedHeight = Math.ceil(options.height / 256) * 256,\n max;\n\n // Compute number of zoomlevels in this tileset\n if (bufferedWidth > bufferedHeight) {\n max = bufferedWidth / 256;\n } else {\n max = bufferedHeight / 256;\n }\n options.maxLevel = Math.ceil(Math.log(max) / Math.log(2)) - 1;\n options.tileSize = 256;\n options.width = bufferedWidth;\n options.height = bufferedHeight;\n\n $.TileSource.apply( this, [ options ] );\n\n};\n\n$.extend( $.TmsTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.TmsTileSource.prototype */{\n\n\n /**\n * Determine if the data and/or url imply the image service is supported by\n * this tile source.\n * @function\n * @param {Object|Array} data\n * @param {String} optional - url\n */\n supports: function( data, url ){\n return ( data.type && \"tiledmapservice\" == data.type );\n },\n\n /**\n *\n * @function\n * @param {Object} data - the raw configuration\n * @param {String} url - the url the data was retreived from if any.\n * @return {Object} options - A dictionary of keyword arguments sufficient\n * to configure this tile sources constructor.\n */\n configure: function( data, url ){\n return data;\n },\n\n\n /**\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n */\n getTileUrl: function( level, x, y ) {\n // Convert from Deep Zoom definition to TMS zoom definition\n var yTiles = this.getNumTiles( level ).y - 1;\n\n return this.tilesUrl + level + \"/\" + x + \"/\" + (yTiles - y) + \".png\";\n }\n});\n\n\n}( OpenSeadragon ));\n","(function($) {\n\n /**\n * @class ZoomifyTileSource\n * @classdesc A tilesource implementation for the zoomify format.\n *\n * A description of the format can be found here:\n * https://ecommons.cornell.edu/bitstream/handle/1813/5410/Introducing_Zoomify_Image.pdf\n *\n * There are two ways of creating a zoomify tilesource for openseadragon\n *\n * 1) Supplying all necessary information in the tilesource object. A minimal example object for this method looks like this:\n *\n * {\n * type: \"zoomifytileservice\",\n * width: 1000,\n * height: 1000,\n * tilesUrl: \"/test/data/zoomify/\"\n * }\n *\n * The tileSize is currently hardcoded to 256 (the usual Zoomify default). The tileUrl must the path to the image _directory_.\n *\n * 2) Loading image metadata from xml file: (CURRENTLY NOT SUPPORTED)\n *\n * When creating zoomify formatted images one \"xml\" like file with name ImageProperties.xml\n * will be created as well. Here is an example of such a file:\n *\n * \n *\n * To use this xml file as metadata source you must supply the path to the ImageProperties.xml file and leave out all other parameters:\n * As stated above, this method of loading a zoomify tilesource is currently not supported\n *\n * {\n * type: \"zoomifytileservice\",\n * tilesUrl: \"/test/data/zoomify/ImageProperties.xml\"\n * }\n\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.TileSource\n * @param {Number} width - the pixel width of the image.\n * @param {Number} height\n * @param {Number} tileSize\n * @param {String} tilesUrl\n */\n $.ZoomifyTileSource = function(options) {\n options.tileSize = 256;\n\n var currentImageSize = {\n x: options.width,\n y: options.height\n };\n options.imageSizes = [{\n x: options.width,\n y: options.height\n }];\n options.gridSize = [this._getGridSize(options.width, options.height, options.tileSize)];\n\n while (parseInt(currentImageSize.x, 10) > options.tileSize || parseInt(currentImageSize.y, 10) > options.tileSize) {\n currentImageSize.x = Math.floor(currentImageSize.x / 2);\n currentImageSize.y = Math.floor(currentImageSize.y / 2);\n options.imageSizes.push({\n x: currentImageSize.x,\n y: currentImageSize.y\n });\n options.gridSize.push(this._getGridSize(currentImageSize.x, currentImageSize.y, options.tileSize));\n }\n options.imageSizes.reverse();\n options.gridSize.reverse();\n options.minLevel = 0;\n options.maxLevel = options.gridSize.length - 1;\n\n OpenSeadragon.TileSource.apply(this, [options]);\n };\n\n $.extend($.ZoomifyTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.ZoomifyTileSource.prototype */ {\n\n //private\n _getGridSize: function(width, height, tileSize) {\n return {\n x: Math.ceil(width / tileSize),\n y: Math.ceil(height / tileSize)\n };\n },\n\n //private\n _calculateAbsoluteTileNumber: function(level, x, y) {\n var num = 0;\n var size = {};\n\n //Sum up all tiles below the level we want the number of tiles\n for (var z = 0; z < level; z++) {\n size = this.gridSize[z];\n num += size.x * size.y;\n }\n //Add the tiles of the level\n size = this.gridSize[level];\n num += size.x * y + x;\n return num;\n },\n\n /**\n * Determine if the data and/or url imply the image service is supported by\n * this tile source.\n * @function\n * @param {Object|Array} data\n * @param {String} optional - url\n */\n supports: function(data, url) {\n return (data.type && \"zoomifytileservice\" == data.type);\n },\n\n /**\n *\n * @function\n * @param {Object} data - the raw configuration\n * @param {String} url - the url the data was retreived from if any.\n * @return {Object} options - A dictionary of keyword arguments sufficient\n * to configure this tile sources constructor.\n */\n configure: function(data, url) {\n return data;\n },\n\n /**\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n */\n getTileUrl: function(level, x, y) {\n //console.log(level);\n var result = 0;\n var num = this._calculateAbsoluteTileNumber(level, x, y);\n result = Math.floor(num / 256);\n return this.tilesUrl + 'TileGroup' + result + '/' + level + '-' + x + '-' + y + '.jpg';\n\n }\n });\n\n}(OpenSeadragon));\n\n","/*\n * OpenSeadragon - LegacyTileSource\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class LegacyTileSource\n * @classdesc The LegacyTileSource allows simple, traditional image pyramids to be loaded\n * into an OpenSeadragon Viewer. Basically, this translates to the historically\n * common practice of starting with a 'master' image, maybe a tiff for example,\n * and generating a set of 'service' images like one or more thumbnails, a medium\n * resolution image and a high resolution image in standard web formats like\n * png or jpg.\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.TileSource\n * @param {Array} levels An array of file descriptions, each is an object with\n * a 'url', a 'width', and a 'height'. Overriding classes can expect more\n * properties but these properties are sufficient for this implementation.\n * Additionally, the levels are required to be listed in order from\n * smallest to largest.\n * @property {Number} aspectRatio\n * @property {Number} dimensions\n * @property {Number} tileSize\n * @property {Number} tileOverlap\n * @property {Number} minLevel\n * @property {Number} maxLevel\n * @property {Array} levels\n */\n$.LegacyTileSource = function( levels ) {\n\n var options,\n width,\n height;\n\n if( $.isArray( levels ) ){\n options = {\n type: 'legacy-image-pyramid',\n levels: levels\n };\n }\n\n //clean up the levels to make sure we support all formats\n options.levels = filterFiles( options.levels );\n\n if ( options.levels.length > 0 ) {\n width = options.levels[ options.levels.length - 1 ].width;\n height = options.levels[ options.levels.length - 1 ].height;\n }\n else {\n width = 0;\n height = 0;\n $.console.error( \"No supported image formats found\" );\n }\n\n $.extend( true, options, {\n width: width,\n height: height,\n tileSize: Math.max( height, width ),\n tileOverlap: 0,\n minLevel: 0,\n maxLevel: options.levels.length > 0 ? options.levels.length - 1 : 0\n } );\n\n $.TileSource.apply( this, [ options ] );\n\n this.levels = options.levels;\n};\n\n$.extend( $.LegacyTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.LegacyTileSource.prototype */{\n /**\n * Determine if the data and/or url imply the image service is supported by\n * this tile source.\n * @function\n * @param {Object|Array} data\n * @param {String} optional - url\n */\n supports: function( data, url ){\n return (\n data.type &&\n \"legacy-image-pyramid\" == data.type\n ) || (\n data.documentElement &&\n \"legacy-image-pyramid\" == data.documentElement.getAttribute('type')\n );\n },\n\n\n /**\n *\n * @function\n * @param {Object|XMLDocument} configuration - the raw configuration\n * @param {String} dataUrl - the url the data was retreived from if any.\n * @return {Object} options - A dictionary of keyword arguments sufficient\n * to configure this tile sources constructor.\n */\n configure: function( configuration, dataUrl ){\n\n var options;\n\n if( !$.isPlainObject(configuration) ){\n\n options = configureFromXML( this, configuration );\n\n }else{\n\n options = configureFromObject( this, configuration );\n }\n\n return options;\n\n },\n\n /**\n * @function\n * @param {Number} level\n */\n getLevelScale: function ( level ) {\n var levelScale = NaN;\n if ( this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel ) {\n levelScale =\n this.levels[ level ].width /\n this.levels[ this.maxLevel ].width;\n }\n return levelScale;\n },\n\n /**\n * @function\n * @param {Number} level\n */\n getNumTiles: function( level ) {\n var scale = this.getLevelScale( level );\n if ( scale ){\n return new $.Point( 1, 1 );\n } else {\n return new $.Point( 0, 0 );\n }\n },\n\n /**\n * This method is not implemented by this class other than to throw an Error\n * announcing you have to implement it. Because of the variety of tile\n * server technologies, and various specifications for building image\n * pyramids, this method is here to allow easy integration.\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n * @throws {Error}\n */\n getTileUrl: function ( level, x, y ) {\n var url = null;\n if ( this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel ) {\n url = this.levels[ level ].url;\n }\n return url;\n }\n} );\n\n/**\n * This method removes any files from the Array which dont conform to our\n * basic requirements for a 'level' in the LegacyTileSource.\n * @private\n * @inner\n * @function\n */\nfunction filterFiles( files ){\n var filtered = [],\n file,\n i;\n for( i = 0; i < files.length; i++ ){\n file = files[ i ];\n if( file.height &&\n file.width &&\n file.url ){\n //This is sufficient to serve as a level\n filtered.push({\n url: file.url,\n width: Number( file.width ),\n height: Number( file.height )\n });\n }\n else {\n $.console.error( 'Unsupported image format: %s', file.url ? file.url : '' );\n }\n }\n\n return filtered.sort(function(a, b) {\n return a.height - b.height;\n });\n\n}\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction configureFromXML( tileSource, xmlDoc ){\n\n if ( !xmlDoc || !xmlDoc.documentElement ) {\n throw new Error( $.getString( \"Errors.Xml\" ) );\n }\n\n var root = xmlDoc.documentElement,\n rootName = root.tagName,\n conf = null,\n levels = [],\n level,\n i;\n\n if ( rootName == \"image\" ) {\n\n try {\n conf = {\n type: root.getAttribute( \"type\" ),\n levels: []\n };\n\n levels = root.getElementsByTagName( \"level\" );\n for ( i = 0; i < levels.length; i++ ) {\n level = levels[ i ];\n\n conf.levels.push({\n url: level.getAttribute( \"url\" ),\n width: parseInt( level.getAttribute( \"width\" ), 10 ),\n height: parseInt( level.getAttribute( \"height\" ), 10 )\n });\n }\n\n return configureFromObject( tileSource, conf );\n\n } catch ( e ) {\n throw (e instanceof Error) ?\n e :\n new Error( 'Unknown error parsing Legacy Image Pyramid XML.' );\n }\n } else if ( rootName == \"collection\" ) {\n throw new Error( 'Legacy Image Pyramid Collections not yet supported.' );\n } else if ( rootName == \"error\" ) {\n throw new Error( 'Error: ' + xmlDoc );\n }\n\n throw new Error( 'Unknown element ' + rootName );\n}\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction configureFromObject( tileSource, configuration ){\n\n return configuration.levels;\n\n}\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - ImageTileSource\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function ($) {\n\n /**\n * @class ImageTileSource\n * @classdesc The ImageTileSource allows a simple image to be loaded\n * into an OpenSeadragon Viewer.\n * There are 2 ways to open an ImageTileSource:\n * 1. viewer.open({type: 'image', url: fooUrl});\n * 2. viewer.open(new OpenSeadragon.ImageTileSource({url: fooUrl}));\n *\n * With the first syntax, the crossOriginPolicy, ajaxWithCredentials and\n * useCanvas options are inherited from the viewer if they are not\n * specified directly in the options object.\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.TileSource\n * @param {Object} options Options object.\n * @param {String} options.url URL of the image\n * @param {Boolean} [options.buildPyramid=true] If set to true (default), a\n * pyramid will be built internally to provide a better downsampling.\n * @param {String|Boolean} [options.crossOriginPolicy=false] Valid values are\n * 'Anonymous', 'use-credentials', and false. If false, image requests will\n * not use CORS preventing internal pyramid building for images from other\n * domains.\n * @param {String|Boolean} [options.ajaxWithCredentials=false] Whether to set\n * the withCredentials XHR flag for AJAX requests (when loading tile sources).\n * @param {Boolean} [options.useCanvas=true] Set to false to prevent any use\n * of the canvas API.\n */\n $.ImageTileSource = function (options) {\n\n options = $.extend({\n buildPyramid: true,\n crossOriginPolicy: false,\n ajaxWithCredentials: false,\n useCanvas: true\n }, options);\n $.TileSource.apply(this, [options]);\n\n };\n\n $.extend($.ImageTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.ImageTileSource.prototype */{\n /**\n * Determine if the data and/or url imply the image service is supported by\n * this tile source.\n * @function\n * @param {Object|Array} data\n * @param {String} optional - url\n */\n supports: function (data, url) {\n return data.type && data.type === \"image\";\n },\n /**\n *\n * @function\n * @param {Object} options - the options\n * @param {String} dataUrl - the url the image was retreived from, if any.\n * @return {Object} options - A dictionary of keyword arguments sufficient\n * to configure this tile sources constructor.\n */\n configure: function (options, dataUrl) {\n return options;\n },\n /**\n * Responsible for retrieving, and caching the\n * image metadata pertinent to this TileSources implementation.\n * @function\n * @param {String} url\n * @throws {Error}\n */\n getImageInfo: function (url) {\n var image = this._image = new Image();\n var _this = this;\n\n if (this.crossOriginPolicy) {\n image.crossOrigin = this.crossOriginPolicy;\n }\n if (this.ajaxWithCredentials) {\n image.useCredentials = this.ajaxWithCredentials;\n }\n\n $.addEvent(image, 'load', function () {\n /* IE8 fix since it has no naturalWidth and naturalHeight */\n _this.width = Object.prototype.hasOwnProperty.call(image, 'naturalWidth') ? image.naturalWidth : image.width;\n _this.height = Object.prototype.hasOwnProperty.call(image, 'naturalHeight') ? image.naturalHeight : image.height;\n _this.aspectRatio = _this.width / _this.height;\n _this.dimensions = new $.Point(_this.width, _this.height);\n _this._tileWidth = _this.width;\n _this._tileHeight = _this.height;\n _this.tileOverlap = 0;\n _this.minLevel = 0;\n _this.levels = _this._buildLevels();\n _this.maxLevel = _this.levels.length - 1;\n\n _this.ready = true;\n\n // Note: this event is documented elsewhere, in TileSource\n _this.raiseEvent('ready', {tileSource: _this});\n });\n\n $.addEvent(image, 'error', function () {\n // Note: this event is documented elsewhere, in TileSource\n _this.raiseEvent('open-failed', {\n message: \"Error loading image at \" + url,\n source: url\n });\n });\n\n image.src = url;\n },\n /**\n * @function\n * @param {Number} level\n */\n getLevelScale: function (level) {\n var levelScale = NaN;\n if (level >= this.minLevel && level <= this.maxLevel) {\n levelScale =\n this.levels[level].width /\n this.levels[this.maxLevel].width;\n }\n return levelScale;\n },\n /**\n * @function\n * @param {Number} level\n */\n getNumTiles: function (level) {\n var scale = this.getLevelScale(level);\n if (scale) {\n return new $.Point(1, 1);\n } else {\n return new $.Point(0, 0);\n }\n },\n /**\n * Retrieves a tile url\n * @function\n * @param {Number} level Level of the tile\n * @param {Number} x x coordinate of the tile\n * @param {Number} y y coordinate of the tile\n */\n getTileUrl: function (level, x, y) {\n var url = null;\n if (level >= this.minLevel && level <= this.maxLevel) {\n url = this.levels[level].url;\n }\n return url;\n },\n /**\n * Retrieves a tile context 2D\n * @function\n * @param {Number} level Level of the tile\n * @param {Number} x x coordinate of the tile\n * @param {Number} y y coordinate of the tile\n */\n getContext2D: function (level, x, y) {\n var context = null;\n if (level >= this.minLevel && level <= this.maxLevel) {\n context = this.levels[level].context2D;\n }\n return context;\n },\n\n // private\n //\n // Builds the differents levels of the pyramid if possible\n // (i.e. if canvas API enabled and no canvas tainting issue).\n _buildLevels: function () {\n var levels = [{\n url: this._image.src,\n /* IE8 fix since it has no naturalWidth and naturalHeight */\n width: Object.prototype.hasOwnProperty.call(this._image, 'naturalWidth') ? this._image.naturalWidth : this._image.width,\n height: Object.prototype.hasOwnProperty.call(this._image, 'naturalHeight') ? this._image.naturalHeight : this._image.height\n }];\n\n if (!this.buildPyramid || !$.supportsCanvas || !this.useCanvas) {\n // We don't need the image anymore. Allows it to be GC.\n delete this._image;\n return levels;\n }\n\n /* IE8 fix since it has no naturalWidth and naturalHeight */\n var currentWidth = Object.prototype.hasOwnProperty.call(this._image, 'naturalWidth') ? this._image.naturalWidth : this._image.width;\n var currentHeight = Object.prototype.hasOwnProperty.call(this._image, 'naturalHeight') ? this._image.naturalHeight : this._image.height;\n\n\n var bigCanvas = document.createElement(\"canvas\");\n var bigContext = bigCanvas.getContext(\"2d\");\n\n bigCanvas.width = currentWidth;\n bigCanvas.height = currentHeight;\n bigContext.drawImage(this._image, 0, 0, currentWidth, currentHeight);\n // We cache the context of the highest level because the browser\n // is a lot faster at downsampling something it already has\n // downsampled before.\n levels[0].context2D = bigContext;\n // We don't need the image anymore. Allows it to be GC.\n delete this._image;\n\n if ($.isCanvasTainted(bigCanvas)) {\n // If the canvas is tainted, we can't compute the pyramid.\n return levels;\n }\n\n // We build smaller levels until either width or height becomes\n // 1 pixel wide.\n while (currentWidth >= 2 && currentHeight >= 2) {\n currentWidth = Math.floor(currentWidth / 2);\n currentHeight = Math.floor(currentHeight / 2);\n var smallCanvas = document.createElement(\"canvas\");\n var smallContext = smallCanvas.getContext(\"2d\");\n smallCanvas.width = currentWidth;\n smallCanvas.height = currentHeight;\n smallContext.drawImage(bigCanvas, 0, 0, currentWidth, currentHeight);\n\n levels.splice(0, 0, {\n context2D: smallContext,\n width: currentWidth,\n height: currentHeight\n });\n\n bigCanvas = smallCanvas;\n bigContext = smallContext;\n }\n return levels;\n }\n });\n\n}(OpenSeadragon));\n","/*\n * OpenSeadragon - TileSourceCollection\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function($) {\n\n// deprecated\n$.TileSourceCollection = function(tileSize, tileSources, rows, layout) {\n $.console.error('TileSourceCollection is deprecated; use World instead');\n};\n\n}(OpenSeadragon));\n","/*\n * OpenSeadragon - Button\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * An enumeration of button states\n * @member ButtonState\n * @memberof OpenSeadragon\n * @static\n * @type {Object}\n * @property {Number} REST\n * @property {Number} GROUP\n * @property {Number} HOVER\n * @property {Number} DOWN\n */\n$.ButtonState = {\n REST: 0,\n GROUP: 1,\n HOVER: 2,\n DOWN: 3\n};\n\n/**\n * @class Button\n * @classdesc Manages events, hover states for individual buttons, tool-tips, as well\n * as fading the buttons out when the user has not interacted with them\n * for a specified period.\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.EventSource\n * @param {Object} options\n * @param {Element} [options.element=null] Element to use as the button. If not specified, an HTML <div> element is created.\n * @param {String} [options.tooltip=null] Provides context help for the button when the\n * user hovers over it.\n * @param {String} [options.srcRest=null] URL of image to use in 'rest' state.\n * @param {String} [options.srcGroup=null] URL of image to use in 'up' state.\n * @param {String} [options.srcHover=null] URL of image to use in 'hover' state.\n * @param {String} [options.srcDown=null] URL of image to use in 'down' state.\n * @param {Number} [options.fadeDelay=0] How long to wait before fading.\n * @param {Number} [options.fadeLength=2000] How long should it take to fade the button.\n * @param {OpenSeadragon.EventHandler} [options.onPress=null] Event handler callback for {@link OpenSeadragon.Button.event:press}.\n * @param {OpenSeadragon.EventHandler} [options.onRelease=null] Event handler callback for {@link OpenSeadragon.Button.event:release}.\n * @param {OpenSeadragon.EventHandler} [options.onClick=null] Event handler callback for {@link OpenSeadragon.Button.event:click}.\n * @param {OpenSeadragon.EventHandler} [options.onEnter=null] Event handler callback for {@link OpenSeadragon.Button.event:enter}.\n * @param {OpenSeadragon.EventHandler} [options.onExit=null] Event handler callback for {@link OpenSeadragon.Button.event:exit}.\n * @param {OpenSeadragon.EventHandler} [options.onFocus=null] Event handler callback for {@link OpenSeadragon.Button.event:focus}.\n * @param {OpenSeadragon.EventHandler} [options.onBlur=null] Event handler callback for {@link OpenSeadragon.Button.event:blur}.\n */\n$.Button = function( options ) {\n\n var _this = this;\n\n $.EventSource.call( this );\n\n $.extend( true, this, {\n\n tooltip: null,\n srcRest: null,\n srcGroup: null,\n srcHover: null,\n srcDown: null,\n clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold,\n clickDistThreshold: $.DEFAULT_SETTINGS.clickDistThreshold,\n /**\n * How long to wait before fading.\n * @member {Number} fadeDelay\n * @memberof OpenSeadragon.Button#\n */\n fadeDelay: 0,\n /**\n * How long should it take to fade the button.\n * @member {Number} fadeLength\n * @memberof OpenSeadragon.Button#\n */\n fadeLength: 2000,\n onPress: null,\n onRelease: null,\n onClick: null,\n onEnter: null,\n onExit: null,\n onFocus: null,\n onBlur: null\n\n }, options );\n\n /**\n * The button element.\n * @member {Element} element\n * @memberof OpenSeadragon.Button#\n */\n this.element = options.element || $.makeNeutralElement(\"div\");\n\n //if the user has specified the element to bind the control to explicitly\n //then do not add the default control images\n if ( !options.element ) {\n this.imgRest = $.makeTransparentImage( this.srcRest );\n this.imgGroup = $.makeTransparentImage( this.srcGroup );\n this.imgHover = $.makeTransparentImage( this.srcHover );\n this.imgDown = $.makeTransparentImage( this.srcDown );\n\n this.imgRest.alt =\n this.imgGroup.alt =\n this.imgHover.alt =\n this.imgDown.alt =\n this.tooltip;\n\n this.element.style.position = \"relative\";\n $.setElementTouchActionNone( this.element );\n\n this.imgGroup.style.position =\n this.imgHover.style.position =\n this.imgDown.style.position =\n \"absolute\";\n\n this.imgGroup.style.top =\n this.imgHover.style.top =\n this.imgDown.style.top =\n \"0px\";\n\n this.imgGroup.style.left =\n this.imgHover.style.left =\n this.imgDown.style.left =\n \"0px\";\n\n this.imgHover.style.visibility =\n this.imgDown.style.visibility =\n \"hidden\";\n\n if ($.Browser.vendor == $.BROWSERS.FIREFOX && $.Browser.version < 3) {\n this.imgGroup.style.top =\n this.imgHover.style.top =\n this.imgDown.style.top =\n \"\";\n }\n\n this.element.appendChild( this.imgRest );\n this.element.appendChild( this.imgGroup );\n this.element.appendChild( this.imgHover );\n this.element.appendChild( this.imgDown );\n }\n\n\n this.addHandler(\"press\", this.onPress);\n this.addHandler(\"release\", this.onRelease);\n this.addHandler(\"click\", this.onClick);\n this.addHandler(\"enter\", this.onEnter);\n this.addHandler(\"exit\", this.onExit);\n this.addHandler(\"focus\", this.onFocus);\n this.addHandler(\"blur\", this.onBlur);\n\n /**\n * The button's current state.\n * @member {OpenSeadragon.ButtonState} currentState\n * @memberof OpenSeadragon.Button#\n */\n this.currentState = $.ButtonState.GROUP;\n\n // When the button last began to fade.\n this.fadeBeginTime = null;\n // Whether this button should fade after user stops interacting with the viewport.\n this.shouldFade = false;\n\n this.element.style.display = \"inline-block\";\n this.element.style.position = \"relative\";\n this.element.title = this.tooltip;\n\n /**\n * Tracks mouse/touch/key events on the button.\n * @member {OpenSeadragon.MouseTracker} tracker\n * @memberof OpenSeadragon.Button#\n */\n this.tracker = new $.MouseTracker({\n\n element: this.element,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n\n enterHandler: function( event ) {\n if ( event.insideElementPressed ) {\n inTo( _this, $.ButtonState.DOWN );\n /**\n * Raised when the cursor enters the Button element.\n *\n * @event enter\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( \"enter\", { originalEvent: event.originalEvent } );\n } else if ( !event.buttonDownAny ) {\n inTo( _this, $.ButtonState.HOVER );\n }\n },\n\n focusHandler: function ( event ) {\n this.enterHandler( event );\n /**\n * Raised when the Button element receives focus.\n *\n * @event focus\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( \"focus\", { originalEvent: event.originalEvent } );\n },\n\n exitHandler: function( event ) {\n outTo( _this, $.ButtonState.GROUP );\n if ( event.insideElementPressed ) {\n /**\n * Raised when the cursor leaves the Button element.\n *\n * @event exit\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( \"exit\", { originalEvent: event.originalEvent } );\n }\n },\n\n blurHandler: function ( event ) {\n this.exitHandler( event );\n /**\n * Raised when the Button element loses focus.\n *\n * @event blur\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( \"blur\", { originalEvent: event.originalEvent } );\n },\n\n pressHandler: function ( event ) {\n inTo( _this, $.ButtonState.DOWN );\n /**\n * Raised when a mouse button is pressed or touch occurs in the Button element.\n *\n * @event press\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( \"press\", { originalEvent: event.originalEvent } );\n },\n\n releaseHandler: function( event ) {\n if ( event.insideElementPressed && event.insideElementReleased ) {\n outTo( _this, $.ButtonState.HOVER );\n /**\n * Raised when the mouse button is released or touch ends in the Button element.\n *\n * @event release\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( \"release\", { originalEvent: event.originalEvent } );\n } else if ( event.insideElementPressed ) {\n outTo( _this, $.ButtonState.GROUP );\n } else {\n inTo( _this, $.ButtonState.HOVER );\n }\n },\n\n clickHandler: function( event ) {\n if ( event.quick ) {\n /**\n * Raised when a mouse button is pressed and released or touch is initiated and ended in the Button element within the time and distance threshold.\n *\n * @event click\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent(\"click\", { originalEvent: event.originalEvent });\n }\n },\n\n keyHandler: function( event ){\n //console.log( \"%s : handling key %s!\", _this.tooltip, event.keyCode);\n if( 13 === event.keyCode ){\n /***\n * Raised when a mouse button is pressed and released or touch is initiated and ended in the Button element within the time and distance threshold.\n *\n * @event click\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( \"click\", { originalEvent: event.originalEvent } );\n /***\n * Raised when the mouse button is released or touch ends in the Button element.\n *\n * @event release\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( \"release\", { originalEvent: event.originalEvent } );\n return false;\n }\n return true;\n }\n\n });\n\n outTo( this, $.ButtonState.REST );\n};\n\n$.extend( $.Button.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.Button.prototype */{\n\n /**\n * TODO: Determine what this function is intended to do and if it's actually\n * useful as an API point.\n * @function\n */\n notifyGroupEnter: function() {\n inTo( this, $.ButtonState.GROUP );\n },\n\n /**\n * TODO: Determine what this function is intended to do and if it's actually\n * useful as an API point.\n * @function\n */\n notifyGroupExit: function() {\n outTo( this, $.ButtonState.REST );\n },\n\n /**\n * @function\n */\n disable: function(){\n this.notifyGroupExit();\n this.element.disabled = true;\n $.setElementOpacity( this.element, 0.2, true );\n },\n\n /**\n * @function\n */\n enable: function(){\n this.element.disabled = false;\n $.setElementOpacity( this.element, 1.0, true );\n this.notifyGroupEnter();\n }\n\n});\n\n\nfunction scheduleFade( button ) {\n $.requestAnimationFrame(function(){\n updateFade( button );\n });\n}\n\nfunction updateFade( button ) {\n var currentTime,\n deltaTime,\n opacity;\n\n if ( button.shouldFade ) {\n currentTime = $.now();\n deltaTime = currentTime - button.fadeBeginTime;\n opacity = 1.0 - deltaTime / button.fadeLength;\n opacity = Math.min( 1.0, opacity );\n opacity = Math.max( 0.0, opacity );\n\n if( button.imgGroup ){\n $.setElementOpacity( button.imgGroup, opacity, true );\n }\n if ( opacity > 0 ) {\n // fade again\n scheduleFade( button );\n }\n }\n}\n\nfunction beginFading( button ) {\n button.shouldFade = true;\n button.fadeBeginTime = $.now() + button.fadeDelay;\n window.setTimeout( function(){\n scheduleFade( button );\n }, button.fadeDelay );\n}\n\nfunction stopFading( button ) {\n button.shouldFade = false;\n if( button.imgGroup ){\n $.setElementOpacity( button.imgGroup, 1.0, true );\n }\n}\n\nfunction inTo( button, newState ) {\n\n if( button.element.disabled ){\n return;\n }\n\n if ( newState >= $.ButtonState.GROUP &&\n button.currentState == $.ButtonState.REST ) {\n stopFading( button );\n button.currentState = $.ButtonState.GROUP;\n }\n\n if ( newState >= $.ButtonState.HOVER &&\n button.currentState == $.ButtonState.GROUP ) {\n if( button.imgHover ){\n button.imgHover.style.visibility = \"\";\n }\n button.currentState = $.ButtonState.HOVER;\n }\n\n if ( newState >= $.ButtonState.DOWN &&\n button.currentState == $.ButtonState.HOVER ) {\n if( button.imgDown ){\n button.imgDown.style.visibility = \"\";\n }\n button.currentState = $.ButtonState.DOWN;\n }\n}\n\n\nfunction outTo( button, newState ) {\n\n if( button.element.disabled ){\n return;\n }\n\n if ( newState <= $.ButtonState.HOVER &&\n button.currentState == $.ButtonState.DOWN ) {\n if( button.imgDown ){\n button.imgDown.style.visibility = \"hidden\";\n }\n button.currentState = $.ButtonState.HOVER;\n }\n\n if ( newState <= $.ButtonState.GROUP &&\n button.currentState == $.ButtonState.HOVER ) {\n if( button.imgHover ){\n button.imgHover.style.visibility = \"hidden\";\n }\n button.currentState = $.ButtonState.GROUP;\n }\n\n if ( newState <= $.ButtonState.REST &&\n button.currentState == $.ButtonState.GROUP ) {\n beginFading( button );\n button.currentState = $.ButtonState.REST;\n }\n}\n\n\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - ButtonGroup\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n/**\n * @class ButtonGroup\n * @classdesc Manages events on groups of buttons.\n *\n * @memberof OpenSeadragon\n * @param {Object} options - A dictionary of settings applied against the entire group of buttons.\n * @param {Array} options.buttons Array of buttons\n * @param {Element} [options.element] Element to use as the container\n **/\n$.ButtonGroup = function( options ) {\n\n $.extend( true, this, {\n /**\n * An array containing the buttons themselves.\n * @member {Array} buttons\n * @memberof OpenSeadragon.ButtonGroup#\n */\n buttons: [],\n clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold,\n clickDistThreshold: $.DEFAULT_SETTINGS.clickDistThreshold,\n labelText: \"\"\n }, options );\n\n // copy the button elements TODO: Why?\n var buttons = this.buttons.concat([]),\n _this = this,\n i;\n\n /**\n * The shared container for the buttons.\n * @member {Element} element\n * @memberof OpenSeadragon.ButtonGroup#\n */\n this.element = options.element || $.makeNeutralElement( \"div\" );\n\n // TODO What if there IS an options.group specified?\n if( !options.group ){\n this.label = $.makeNeutralElement( \"label\" );\n //TODO: support labels for ButtonGroups\n //this.label.innerHTML = this.labelText;\n this.element.style.display = \"inline-block\";\n this.element.appendChild( this.label );\n for ( i = 0; i < buttons.length; i++ ) {\n this.element.appendChild( buttons[ i ].element );\n }\n }\n\n $.setElementTouchActionNone( this.element );\n\n /**\n * Tracks mouse/touch/key events accross the group of buttons.\n * @member {OpenSeadragon.MouseTracker} tracker\n * @memberof OpenSeadragon.ButtonGroup#\n */\n this.tracker = new $.MouseTracker({\n element: this.element,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n enterHandler: function ( event ) {\n var i;\n for ( i = 0; i < _this.buttons.length; i++ ) {\n _this.buttons[ i ].notifyGroupEnter();\n }\n },\n exitHandler: function ( event ) {\n var i;\n if ( !event.insideElementPressed ) {\n for ( i = 0; i < _this.buttons.length; i++ ) {\n _this.buttons[ i ].notifyGroupExit();\n }\n }\n },\n });\n};\n\n/** @lends OpenSeadragon.ButtonGroup.prototype */\n$.ButtonGroup.prototype = {\n\n /**\n * TODO: Figure out why this is used on the public API and if a more useful\n * api can be created.\n * @function\n * @private\n */\n emulateEnter: function() {\n this.tracker.enterHandler( { eventSource: this.tracker } );\n },\n\n /**\n * TODO: Figure out why this is used on the public API and if a more useful\n * api can be created.\n * @function\n * @private\n */\n emulateExit: function() {\n this.tracker.exitHandler( { eventSource: this.tracker } );\n }\n};\n\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - Rect\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function($) {\n\n/**\n * @class Rect\n * @classdesc A Rectangle is described by it top left coordinates (x, y), width,\n * height and degrees of rotation around (x, y).\n * Note that the coordinate system used is the one commonly used with images:\n * x increases when going to the right\n * y increases when going to the bottom\n * degrees increases clockwise with 0 being the horizontal\n *\n * The constructor normalizes the rectangle to always have 0 <= degrees < 90\n *\n * @memberof OpenSeadragon\n * @param {Number} [x=0] The vector component 'x'.\n * @param {Number} [y=0] The vector component 'y'.\n * @param {Number} [width=0] The vector component 'width'.\n * @param {Number} [height=0] The vector component 'height'.\n * @param {Number} [degrees=0] Rotation of the rectangle around (x,y) in degrees.\n */\n$.Rect = function(x, y, width, height, degrees) {\n /**\n * The vector component 'x'.\n * @member {Number} x\n * @memberof OpenSeadragon.Rect#\n */\n this.x = typeof(x) === \"number\" ? x : 0;\n /**\n * The vector component 'y'.\n * @member {Number} y\n * @memberof OpenSeadragon.Rect#\n */\n this.y = typeof(y) === \"number\" ? y : 0;\n /**\n * The vector component 'width'.\n * @member {Number} width\n * @memberof OpenSeadragon.Rect#\n */\n this.width = typeof(width) === \"number\" ? width : 0;\n /**\n * The vector component 'height'.\n * @member {Number} height\n * @memberof OpenSeadragon.Rect#\n */\n this.height = typeof(height) === \"number\" ? height : 0;\n\n this.degrees = typeof(degrees) === \"number\" ? degrees : 0;\n\n // Normalizes the rectangle.\n this.degrees = $.positiveModulo(this.degrees, 360);\n var newTopLeft, newWidth;\n if (this.degrees >= 270) {\n newTopLeft = this.getTopRight();\n this.x = newTopLeft.x;\n this.y = newTopLeft.y;\n newWidth = this.height;\n this.height = this.width;\n this.width = newWidth;\n this.degrees -= 270;\n } else if (this.degrees >= 180) {\n newTopLeft = this.getBottomRight();\n this.x = newTopLeft.x;\n this.y = newTopLeft.y;\n this.degrees -= 180;\n } else if (this.degrees >= 90) {\n newTopLeft = this.getBottomLeft();\n this.x = newTopLeft.x;\n this.y = newTopLeft.y;\n newWidth = this.height;\n this.height = this.width;\n this.width = newWidth;\n this.degrees -= 90;\n }\n};\n\n/**\n * Builds a rectangle having the 3 specified points as summits.\n * @static\n * @memberof OpenSeadragon.Rect\n * @param {OpenSeadragon.Point} topLeft\n * @param {OpenSeadragon.Point} topRight\n * @param {OpenSeadragon.Point} bottomLeft\n * @returns {OpenSeadragon.Rect}\n */\n$.Rect.fromSummits = function(topLeft, topRight, bottomLeft) {\n var width = topLeft.distanceTo(topRight);\n var height = topLeft.distanceTo(bottomLeft);\n var diff = topRight.minus(topLeft);\n var radians = Math.atan(diff.y / diff.x);\n if (diff.x < 0) {\n radians += Math.PI;\n } else if (diff.y < 0) {\n radians += 2 * Math.PI;\n }\n return new $.Rect(\n topLeft.x,\n topLeft.y,\n width,\n height,\n radians / Math.PI * 180);\n};\n\n/** @lends OpenSeadragon.Rect.prototype */\n$.Rect.prototype = {\n /**\n * @function\n * @returns {OpenSeadragon.Rect} a duplicate of this Rect\n */\n clone: function() {\n return new $.Rect(\n this.x,\n this.y,\n this.width,\n this.height,\n this.degrees);\n },\n\n /**\n * The aspect ratio is simply the ratio of width to height.\n * @function\n * @returns {Number} The ratio of width to height.\n */\n getAspectRatio: function() {\n return this.width / this.height;\n },\n\n /**\n * Provides the coordinates of the upper-left corner of the rectangle as a\n * point.\n * @function\n * @returns {OpenSeadragon.Point} The coordinate of the upper-left corner of\n * the rectangle.\n */\n getTopLeft: function() {\n return new $.Point(\n this.x,\n this.y\n );\n },\n\n /**\n * Provides the coordinates of the bottom-right corner of the rectangle as a\n * point.\n * @function\n * @returns {OpenSeadragon.Point} The coordinate of the bottom-right corner of\n * the rectangle.\n */\n getBottomRight: function() {\n return new $.Point(this.x + this.width, this.y + this.height)\n .rotate(this.degrees, this.getTopLeft());\n },\n\n /**\n * Provides the coordinates of the top-right corner of the rectangle as a\n * point.\n * @function\n * @returns {OpenSeadragon.Point} The coordinate of the top-right corner of\n * the rectangle.\n */\n getTopRight: function() {\n return new $.Point(this.x + this.width, this.y)\n .rotate(this.degrees, this.getTopLeft());\n },\n\n /**\n * Provides the coordinates of the bottom-left corner of the rectangle as a\n * point.\n * @function\n * @returns {OpenSeadragon.Point} The coordinate of the bottom-left corner of\n * the rectangle.\n */\n getBottomLeft: function() {\n return new $.Point(this.x, this.y + this.height)\n .rotate(this.degrees, this.getTopLeft());\n },\n\n /**\n * Computes the center of the rectangle.\n * @function\n * @returns {OpenSeadragon.Point} The center of the rectangle as represented\n * as represented by a 2-dimensional vector (x,y)\n */\n getCenter: function() {\n return new $.Point(\n this.x + this.width / 2.0,\n this.y + this.height / 2.0\n ).rotate(this.degrees, this.getTopLeft());\n },\n\n /**\n * Returns the width and height component as a vector OpenSeadragon.Point\n * @function\n * @returns {OpenSeadragon.Point} The 2 dimensional vector representing the\n * the width and height of the rectangle.\n */\n getSize: function() {\n return new $.Point(this.width, this.height);\n },\n\n /**\n * Determines if two Rectangles have equivalent components.\n * @function\n * @param {OpenSeadragon.Rect} rectangle The Rectangle to compare to.\n * @return {Boolean} 'true' if all components are equal, otherwise 'false'.\n */\n equals: function(other) {\n return (other instanceof $.Rect) &&\n this.x === other.x &&\n this.y === other.y &&\n this.width === other.width &&\n this.height === other.height &&\n this.degrees === other.degrees;\n },\n\n /**\n * Multiply all dimensions (except degrees) in this Rect by a factor and\n * return a new Rect.\n * @function\n * @param {Number} factor The factor to multiply vector components.\n * @returns {OpenSeadragon.Rect} A new rect representing the multiplication\n * of the vector components by the factor\n */\n times: function(factor) {\n return new $.Rect(\n this.x * factor,\n this.y * factor,\n this.width * factor,\n this.height * factor,\n this.degrees);\n },\n\n /**\n * Translate/move this Rect by a vector and return new Rect.\n * @function\n * @param {OpenSeadragon.Point} delta The translation vector.\n * @returns {OpenSeadragon.Rect} A new rect with altered position\n */\n translate: function(delta) {\n return new $.Rect(\n this.x + delta.x,\n this.y + delta.y,\n this.width,\n this.height,\n this.degrees);\n },\n\n /**\n * Returns the smallest rectangle that will contain this and the given\n * rectangle bounding boxes.\n * @param {OpenSeadragon.Rect} rect\n * @return {OpenSeadragon.Rect} The new rectangle.\n */\n union: function(rect) {\n var thisBoundingBox = this.getBoundingBox();\n var otherBoundingBox = rect.getBoundingBox();\n\n var left = Math.min(thisBoundingBox.x, otherBoundingBox.x);\n var top = Math.min(thisBoundingBox.y, otherBoundingBox.y);\n var right = Math.max(\n thisBoundingBox.x + thisBoundingBox.width,\n otherBoundingBox.x + otherBoundingBox.width);\n var bottom = Math.max(\n thisBoundingBox.y + thisBoundingBox.height,\n otherBoundingBox.y + otherBoundingBox.height);\n\n return new $.Rect(\n left,\n top,\n right - left,\n bottom - top);\n },\n\n /**\n * Returns the bounding box of the intersection of this rectangle with the\n * given rectangle.\n * @param {OpenSeadragon.Rect} rect\n * @return {OpenSeadragon.Rect} the bounding box of the intersection\n * or null if the rectangles don't intersect.\n */\n intersection: function(rect) {\n // Simplified version of Weiler Atherton clipping algorithm\n // https://en.wikipedia.org/wiki/Weiler%E2%80%93Atherton_clipping_algorithm\n // Because we just want the bounding box of the intersection,\n // we can just compute the bounding box of:\n // 1. all the summits of this which are inside rect\n // 2. all the summits of rect which are inside this\n // 3. all the intersections of rect and this\n var EPSILON = 0.0000000001;\n\n var intersectionPoints = [];\n\n var thisTopLeft = this.getTopLeft();\n if (rect.containsPoint(thisTopLeft, EPSILON)) {\n intersectionPoints.push(thisTopLeft);\n }\n var thisTopRight = this.getTopRight();\n if (rect.containsPoint(thisTopRight, EPSILON)) {\n intersectionPoints.push(thisTopRight);\n }\n var thisBottomLeft = this.getBottomLeft();\n if (rect.containsPoint(thisBottomLeft, EPSILON)) {\n intersectionPoints.push(thisBottomLeft);\n }\n var thisBottomRight = this.getBottomRight();\n if (rect.containsPoint(thisBottomRight, EPSILON)) {\n intersectionPoints.push(thisBottomRight);\n }\n\n var rectTopLeft = rect.getTopLeft();\n if (this.containsPoint(rectTopLeft, EPSILON)) {\n intersectionPoints.push(rectTopLeft);\n }\n var rectTopRight = rect.getTopRight();\n if (this.containsPoint(rectTopRight, EPSILON)) {\n intersectionPoints.push(rectTopRight);\n }\n var rectBottomLeft = rect.getBottomLeft();\n if (this.containsPoint(rectBottomLeft, EPSILON)) {\n intersectionPoints.push(rectBottomLeft);\n }\n var rectBottomRight = rect.getBottomRight();\n if (this.containsPoint(rectBottomRight, EPSILON)) {\n intersectionPoints.push(rectBottomRight);\n }\n\n var thisSegments = this._getSegments();\n var rectSegments = rect._getSegments();\n for (var i = 0; i < thisSegments.length; i++) {\n var thisSegment = thisSegments[i];\n for (var j = 0; j < rectSegments.length; j++) {\n var rectSegment = rectSegments[j];\n var intersect = getIntersection(thisSegment[0], thisSegment[1],\n rectSegment[0], rectSegment[1]);\n if (intersect) {\n intersectionPoints.push(intersect);\n }\n }\n }\n\n // Get intersection point of segments [a,b] and [c,d]\n function getIntersection(a, b, c, d) {\n // http://stackoverflow.com/a/1968345/1440403\n var abVector = b.minus(a);\n var cdVector = d.minus(c);\n\n var denom = -cdVector.x * abVector.y + abVector.x * cdVector.y;\n if (denom === 0) {\n return null;\n }\n\n var s = (abVector.x * (a.y - c.y) - abVector.y * (a.x - c.x)) / denom;\n var t = (cdVector.x * (a.y - c.y) - cdVector.y * (a.x - c.x)) / denom;\n\n if (-EPSILON <= s && s <= 1 - EPSILON &&\n -EPSILON <= t && t <= 1 - EPSILON) {\n return new $.Point(a.x + t * abVector.x, a.y + t * abVector.y);\n }\n return null;\n }\n\n if (intersectionPoints.length === 0) {\n return null;\n }\n\n var minX = intersectionPoints[0].x;\n var maxX = intersectionPoints[0].x;\n var minY = intersectionPoints[0].y;\n var maxY = intersectionPoints[0].y;\n for (var k = 1; k < intersectionPoints.length; k++) {\n var point = intersectionPoints[k];\n if (point.x < minX) {\n minX = point.x;\n }\n if (point.x > maxX) {\n maxX = point.x;\n }\n if (point.y < minY) {\n minY = point.y;\n }\n if (point.y > maxY) {\n maxY = point.y;\n }\n }\n return new $.Rect(minX, minY, maxX - minX, maxY - minY);\n },\n\n // private\n _getSegments: function() {\n var topLeft = this.getTopLeft();\n var topRight = this.getTopRight();\n var bottomLeft = this.getBottomLeft();\n var bottomRight = this.getBottomRight();\n return [[topLeft, topRight],\n [topRight, bottomRight],\n [bottomRight, bottomLeft],\n [bottomLeft, topLeft]];\n },\n\n /**\n * Rotates a rectangle around a point.\n * @function\n * @param {Number} degrees The angle in degrees to rotate.\n * @param {OpenSeadragon.Point} [pivot] The point about which to rotate.\n * Defaults to the center of the rectangle.\n * @return {OpenSeadragon.Rect}\n */\n rotate: function(degrees, pivot) {\n degrees = $.positiveModulo(degrees, 360);\n if (degrees === 0) {\n return this.clone();\n }\n\n pivot = pivot || this.getCenter();\n var newTopLeft = this.getTopLeft().rotate(degrees, pivot);\n var newTopRight = this.getTopRight().rotate(degrees, pivot);\n\n var diff = newTopRight.minus(newTopLeft);\n // Handle floating point error\n diff = diff.apply(function(x) {\n var EPSILON = 1e-15;\n return Math.abs(x) < EPSILON ? 0 : x;\n });\n var radians = Math.atan(diff.y / diff.x);\n if (diff.x < 0) {\n radians += Math.PI;\n } else if (diff.y < 0) {\n radians += 2 * Math.PI;\n }\n return new $.Rect(\n newTopLeft.x,\n newTopLeft.y,\n this.width,\n this.height,\n radians / Math.PI * 180);\n },\n\n /**\n * Retrieves the smallest horizontal (degrees=0) rectangle which contains\n * this rectangle.\n * @returns {OpenSeadragon.Rect}\n */\n getBoundingBox: function() {\n if (this.degrees === 0) {\n return this.clone();\n }\n var topLeft = this.getTopLeft();\n var topRight = this.getTopRight();\n var bottomLeft = this.getBottomLeft();\n var bottomRight = this.getBottomRight();\n var minX = Math.min(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x);\n var maxX = Math.max(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x);\n var minY = Math.min(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y);\n var maxY = Math.max(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y);\n return new $.Rect(\n minX,\n minY,\n maxX - minX,\n maxY - minY);\n },\n\n /**\n * Retrieves the smallest horizontal (degrees=0) rectangle which contains\n * this rectangle and has integers x, y, width and height\n * @returns {OpenSeadragon.Rect}\n */\n getIntegerBoundingBox: function() {\n var boundingBox = this.getBoundingBox();\n var x = Math.floor(boundingBox.x);\n var y = Math.floor(boundingBox.y);\n var width = Math.ceil(boundingBox.width + boundingBox.x - x);\n var height = Math.ceil(boundingBox.height + boundingBox.y - y);\n return new $.Rect(x, y, width, height);\n },\n\n /**\n * Determines whether a point is inside this rectangle (edge included).\n * @function\n * @param {OpenSeadragon.Point} point\n * @param {Number} [epsilon=0] the margin of error allowed\n * @returns {Boolean} true if the point is inside this rectangle, false\n * otherwise.\n */\n containsPoint: function(point, epsilon) {\n epsilon = epsilon || 0;\n\n // See http://stackoverflow.com/a/2752754/1440403 for explanation\n var topLeft = this.getTopLeft();\n var topRight = this.getTopRight();\n var bottomLeft = this.getBottomLeft();\n var topDiff = topRight.minus(topLeft);\n var leftDiff = bottomLeft.minus(topLeft);\n\n return ((point.x - topLeft.x) * topDiff.x +\n (point.y - topLeft.y) * topDiff.y >= -epsilon) &&\n\n ((point.x - topRight.x) * topDiff.x +\n (point.y - topRight.y) * topDiff.y <= epsilon) &&\n\n ((point.x - topLeft.x) * leftDiff.x +\n (point.y - topLeft.y) * leftDiff.y >= -epsilon) &&\n\n ((point.x - bottomLeft.x) * leftDiff.x +\n (point.y - bottomLeft.y) * leftDiff.y <= epsilon);\n },\n\n /**\n * Provides a string representation of the rectangle which is useful for\n * debugging.\n * @function\n * @returns {String} A string representation of the rectangle.\n */\n toString: function() {\n return \"[\" +\n (Math.round(this.x * 100) / 100) + \", \" +\n (Math.round(this.y * 100) / 100) + \", \" +\n (Math.round(this.width * 100) / 100) + \"x\" +\n (Math.round(this.height * 100) / 100) + \", \" +\n (Math.round(this.degrees * 100) / 100) + \"deg\" +\n \"]\";\n }\n};\n\n\n}(OpenSeadragon));\n","/*\n * OpenSeadragon - ReferenceStrip\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function ( $ ) {\n\n// dictionary from id to private properties\nvar THIS = {};\n\n/**\n * The CollectionDrawer is a reimplementation if the Drawer API that\n * focuses on allowing a viewport to be redefined as a collection\n * of smaller viewports, defined by a clear number of rows and / or\n * columns of which each item in the matrix of viewports has its own\n * source.\n *\n * This idea is a reexpression of the idea of dzi collections\n * which allows a clearer algorithm to reuse the tile sources already\n * supported by OpenSeadragon, in heterogenious or homogenious\n * sequences just like mixed groups already supported by the viewer\n * for the purpose of image sequnces.\n *\n * TODO: The difficult part of this feature is figuring out how to express\n * this functionality as a combination of the functionality already\n * provided by Drawer, Viewport, TileSource, and Navigator. It may\n * require better abstraction at those points in order to effeciently\n * reuse those paradigms.\n */\n/**\n * @class ReferenceStrip\n * @memberof OpenSeadragon\n * @param {Object} options\n */\n$.ReferenceStrip = function ( options ) {\n\n var _this = this,\n viewer = options.viewer,\n viewerSize = $.getElementSize( viewer.element ),\n element,\n style,\n i;\n\n //We may need to create a new element and id if they did not\n //provide the id for the existing element\n if ( !options.id ) {\n options.id = 'referencestrip-' + $.now();\n this.element = $.makeNeutralElement( \"div\" );\n this.element.id = options.id;\n this.element.className = 'referencestrip';\n }\n\n options = $.extend( true, {\n sizeRatio: $.DEFAULT_SETTINGS.referenceStripSizeRatio,\n position: $.DEFAULT_SETTINGS.referenceStripPosition,\n scroll: $.DEFAULT_SETTINGS.referenceStripScroll,\n clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold\n }, options, {\n //required overrides\n element: this.element,\n //These need to be overridden to prevent recursion since\n //the navigator is a viewer and a viewer has a navigator\n showNavigator: false,\n mouseNavEnabled: false,\n showNavigationControl: false,\n showSequenceControl: false\n } );\n\n $.extend( this, options );\n //Private state properties\n THIS[this.id] = {\n \"animating\": false\n };\n\n this.minPixelRatio = this.viewer.minPixelRatio;\n\n style = this.element.style;\n style.marginTop = '0px';\n style.marginRight = '0px';\n style.marginBottom = '0px';\n style.marginLeft = '0px';\n style.left = '0px';\n style.bottom = '0px';\n style.border = '0px';\n style.background = '#000';\n style.position = 'relative';\n\n $.setElementTouchActionNone( this.element );\n\n $.setElementOpacity( this.element, 0.8 );\n\n this.viewer = viewer;\n this.innerTracker = new $.MouseTracker( {\n element: this.element,\n dragHandler: $.delegate( this, onStripDrag ),\n scrollHandler: $.delegate( this, onStripScroll ),\n enterHandler: $.delegate( this, onStripEnter ),\n exitHandler: $.delegate( this, onStripExit ),\n keyDownHandler: $.delegate( this, onKeyDown ),\n keyHandler: $.delegate( this, onKeyPress )\n } );\n\n //Controls the position and orientation of the reference strip and sets the\n //appropriate width and height\n if ( options.width && options.height ) {\n this.element.style.width = options.width + 'px';\n this.element.style.height = options.height + 'px';\n viewer.addControl(\n this.element,\n { anchor: $.ControlAnchor.BOTTOM_LEFT }\n );\n } else {\n if ( \"horizontal\" == options.scroll ) {\n this.element.style.width = (\n viewerSize.x *\n options.sizeRatio *\n viewer.tileSources.length\n ) + ( 12 * viewer.tileSources.length ) + 'px';\n\n this.element.style.height = (\n viewerSize.y *\n options.sizeRatio\n ) + 'px';\n\n viewer.addControl(\n this.element,\n { anchor: $.ControlAnchor.BOTTOM_LEFT }\n );\n } else {\n this.element.style.height = (\n viewerSize.y *\n options.sizeRatio *\n viewer.tileSources.length\n ) + ( 12 * viewer.tileSources.length ) + 'px';\n\n this.element.style.width = (\n viewerSize.x *\n options.sizeRatio\n ) + 'px';\n\n viewer.addControl(\n this.element,\n { anchor: $.ControlAnchor.TOP_LEFT }\n );\n\n }\n }\n\n this.panelWidth = ( viewerSize.x * this.sizeRatio ) + 8;\n this.panelHeight = ( viewerSize.y * this.sizeRatio ) + 8;\n this.panels = [];\n this.miniViewers = {};\n\n /*jshint loopfunc:true*/\n for ( i = 0; i < viewer.tileSources.length; i++ ) {\n\n element = $.makeNeutralElement( 'div' );\n element.id = this.element.id + \"-\" + i;\n\n element.style.width = _this.panelWidth + 'px';\n element.style.height = _this.panelHeight + 'px';\n element.style.display = 'inline';\n element.style.float = 'left'; //Webkit\n element.style.cssFloat = 'left'; //Firefox\n element.style.styleFloat = 'left'; //IE\n element.style.padding = '2px';\n $.setElementTouchActionNone( element );\n\n element.innerTracker = new $.MouseTracker( {\n element: element,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n pressHandler: function ( event ) {\n event.eventSource.dragging = $.now();\n },\n releaseHandler: function ( event ) {\n var tracker = event.eventSource,\n id = tracker.element.id,\n page = Number( id.split( '-' )[2] ),\n now = $.now();\n\n if ( event.insideElementPressed &&\n event.insideElementReleased &&\n tracker.dragging &&\n ( now - tracker.dragging ) < tracker.clickTimeThreshold ) {\n tracker.dragging = null;\n viewer.goToPage( page );\n }\n }\n } );\n\n this.element.appendChild( element );\n\n element.activePanel = false;\n\n this.panels.push( element );\n\n }\n loadPanels( this, this.scroll == 'vertical' ? viewerSize.y : viewerSize.x, 0 );\n this.setFocus( 0 );\n\n};\n\n$.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.ReferenceStrip.prototype */{\n\n /**\n * @function\n */\n setFocus: function ( page ) {\n var element = $.getElement( this.element.id + '-' + page ),\n viewerSize = $.getElementSize( this.viewer.canvas ),\n scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ),\n scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ),\n offsetLeft = -Number( this.element.style.marginLeft.replace( 'px', '' ) ),\n offsetTop = -Number( this.element.style.marginTop.replace( 'px', '' ) ),\n offset;\n\n if ( this.currentSelected !== element ) {\n if ( this.currentSelected ) {\n this.currentSelected.style.background = '#000';\n }\n this.currentSelected = element;\n this.currentSelected.style.background = '#999';\n\n if ( 'horizontal' == this.scroll ) {\n //right left\n offset = ( Number( page ) ) * ( this.panelWidth + 3 );\n if ( offset > offsetLeft + viewerSize.x - this.panelWidth ) {\n offset = Math.min( offset, ( scrollWidth - viewerSize.x ) );\n this.element.style.marginLeft = -offset + 'px';\n loadPanels( this, viewerSize.x, -offset );\n } else if ( offset < offsetLeft ) {\n offset = Math.max( 0, offset - viewerSize.x / 2 );\n this.element.style.marginLeft = -offset + 'px';\n loadPanels( this, viewerSize.x, -offset );\n }\n } else {\n offset = ( Number( page ) ) * ( this.panelHeight + 3 );\n if ( offset > offsetTop + viewerSize.y - this.panelHeight ) {\n offset = Math.min( offset, ( scrollHeight - viewerSize.y ) );\n this.element.style.marginTop = -offset + 'px';\n loadPanels( this, viewerSize.y, -offset );\n } else if ( offset < offsetTop ) {\n offset = Math.max( 0, offset - viewerSize.y / 2 );\n this.element.style.marginTop = -offset + 'px';\n loadPanels( this, viewerSize.y, -offset );\n }\n }\n\n this.currentPage = page;\n onStripEnter.call( this, { eventSource: this.innerTracker } );\n }\n },\n\n /**\n * @function\n */\n update: function () {\n if ( THIS[this.id].animating ) {\n $.console.log( 'image reference strip update' );\n return true;\n }\n return false;\n },\n\n // Overrides Viewer.destroy\n destroy: function() {\n if (this.miniViewers) {\n for (var key in this.miniViewers) {\n this.miniViewers[key].destroy();\n }\n }\n\n if (this.element) {\n this.element.parentNode.removeChild(this.element);\n }\n }\n\n} );\n\n\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onStripDrag( event ) {\n\n var offsetLeft = Number( this.element.style.marginLeft.replace( 'px', '' ) ),\n offsetTop = Number( this.element.style.marginTop.replace( 'px', '' ) ),\n scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ),\n scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ),\n viewerSize = $.getElementSize( this.viewer.canvas );\n this.dragging = true;\n if ( this.element ) {\n if ( 'horizontal' == this.scroll ) {\n if ( -event.delta.x > 0 ) {\n //forward\n if ( offsetLeft > -( scrollWidth - viewerSize.x ) ) {\n this.element.style.marginLeft = ( offsetLeft + ( event.delta.x * 2 ) ) + 'px';\n loadPanels( this, viewerSize.x, offsetLeft + ( event.delta.x * 2 ) );\n }\n } else if ( -event.delta.x < 0 ) {\n //reverse\n if ( offsetLeft < 0 ) {\n this.element.style.marginLeft = ( offsetLeft + ( event.delta.x * 2 ) ) + 'px';\n loadPanels( this, viewerSize.x, offsetLeft + ( event.delta.x * 2 ) );\n }\n }\n } else {\n if ( -event.delta.y > 0 ) {\n //forward\n if ( offsetTop > -( scrollHeight - viewerSize.y ) ) {\n this.element.style.marginTop = ( offsetTop + ( event.delta.y * 2 ) ) + 'px';\n loadPanels( this, viewerSize.y, offsetTop + ( event.delta.y * 2 ) );\n }\n } else if ( -event.delta.y < 0 ) {\n //reverse\n if ( offsetTop < 0 ) {\n this.element.style.marginTop = ( offsetTop + ( event.delta.y * 2 ) ) + 'px';\n loadPanels( this, viewerSize.y, offsetTop + ( event.delta.y * 2 ) );\n }\n }\n }\n }\n return false;\n\n}\n\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onStripScroll( event ) {\n var offsetLeft = Number( this.element.style.marginLeft.replace( 'px', '' ) ),\n offsetTop = Number( this.element.style.marginTop.replace( 'px', '' ) ),\n scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ),\n scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ),\n viewerSize = $.getElementSize( this.viewer.canvas );\n if ( this.element ) {\n if ( 'horizontal' == this.scroll ) {\n if ( event.scroll > 0 ) {\n //forward\n if ( offsetLeft > -( scrollWidth - viewerSize.x ) ) {\n this.element.style.marginLeft = ( offsetLeft - ( event.scroll * 60 ) ) + 'px';\n loadPanels( this, viewerSize.x, offsetLeft - ( event.scroll * 60 ) );\n }\n } else if ( event.scroll < 0 ) {\n //reverse\n if ( offsetLeft < 0 ) {\n this.element.style.marginLeft = ( offsetLeft - ( event.scroll * 60 ) ) + 'px';\n loadPanels( this, viewerSize.x, offsetLeft - ( event.scroll * 60 ) );\n }\n }\n } else {\n if ( event.scroll < 0 ) {\n //scroll up\n if ( offsetTop > viewerSize.y - scrollHeight ) {\n this.element.style.marginTop = ( offsetTop + ( event.scroll * 60 ) ) + 'px';\n loadPanels( this, viewerSize.y, offsetTop + ( event.scroll * 60 ) );\n }\n } else if ( event.scroll > 0 ) {\n //scroll dowm\n if ( offsetTop < 0 ) {\n this.element.style.marginTop = ( offsetTop + ( event.scroll * 60 ) ) + 'px';\n loadPanels( this, viewerSize.y, offsetTop + ( event.scroll * 60 ) );\n }\n }\n }\n }\n //cancels event\n return false;\n}\n\n\nfunction loadPanels( strip, viewerSize, scroll ) {\n var panelSize,\n activePanelsStart,\n activePanelsEnd,\n miniViewer,\n style,\n i,\n element;\n if ( 'horizontal' == strip.scroll ) {\n panelSize = strip.panelWidth;\n } else {\n panelSize = strip.panelHeight;\n }\n activePanelsStart = Math.ceil( viewerSize / panelSize ) + 5;\n activePanelsEnd = Math.ceil( ( Math.abs( scroll ) + viewerSize ) / panelSize ) + 1;\n activePanelsStart = activePanelsEnd - activePanelsStart;\n activePanelsStart = activePanelsStart < 0 ? 0 : activePanelsStart;\n\n for ( i = activePanelsStart; i < activePanelsEnd && i < strip.panels.length; i++ ) {\n element = strip.panels[i];\n if ( !element.activePanel ) {\n var miniTileSource;\n var originalTileSource = strip.viewer.tileSources[i];\n if (originalTileSource.referenceStripThumbnailUrl) {\n miniTileSource = {\n type: 'image',\n url: originalTileSource.referenceStripThumbnailUrl\n };\n } else {\n miniTileSource = originalTileSource;\n }\n miniViewer = new $.Viewer( {\n id: element.id,\n tileSources: [miniTileSource],\n element: element,\n navigatorSizeRatio: strip.sizeRatio,\n showNavigator: false,\n mouseNavEnabled: false,\n showNavigationControl: false,\n showSequenceControl: false,\n immediateRender: true,\n blendTime: 0,\n animationTime: 0\n } );\n\n miniViewer.displayRegion = $.makeNeutralElement( \"div\" );\n miniViewer.displayRegion.id = element.id + '-displayregion';\n miniViewer.displayRegion.className = 'displayregion';\n\n style = miniViewer.displayRegion.style;\n style.position = 'relative';\n style.top = '0px';\n style.left = '0px';\n style.fontSize = '0px';\n style.overflow = 'hidden';\n style.float = 'left'; //Webkit\n style.cssFloat = 'left'; //Firefox\n style.styleFloat = 'left'; //IE\n style.zIndex = 999999999;\n style.cursor = 'default';\n style.width = ( strip.panelWidth - 4 ) + 'px';\n style.height = ( strip.panelHeight - 4 ) + 'px';\n\n // TODO: What is this for? Future keyboard navigation support?\n miniViewer.displayRegion.innerTracker = new $.MouseTracker( {\n element: miniViewer.displayRegion,\n startDisabled: true\n } );\n\n element.getElementsByTagName( 'div' )[0].appendChild(\n miniViewer.displayRegion\n );\n\n strip.miniViewers[element.id] = miniViewer;\n\n element.activePanel = true;\n }\n }\n}\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onStripEnter( event ) {\n var element = event.eventSource.element;\n\n //$.setElementOpacity(element, 0.8);\n\n //element.style.border = '1px solid #555';\n //element.style.background = '#000';\n\n if ( 'horizontal' == this.scroll ) {\n\n //element.style.paddingTop = \"0px\";\n element.style.marginBottom = \"0px\";\n\n } else {\n\n //element.style.paddingRight = \"0px\";\n element.style.marginLeft = \"0px\";\n\n }\n return false;\n}\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onStripExit( event ) {\n var element = event.eventSource.element;\n\n if ( 'horizontal' == this.scroll ) {\n\n //element.style.paddingTop = \"10px\";\n element.style.marginBottom = \"-\" + ( $.getElementSize( element ).y / 2 ) + \"px\";\n\n } else {\n\n //element.style.paddingRight = \"10px\";\n element.style.marginLeft = \"-\" + ( $.getElementSize( element ).x / 2 ) + \"px\";\n\n }\n return false;\n}\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onKeyDown( event ) {\n //console.log( event.keyCode );\n\n if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) {\n switch ( event.keyCode ) {\n case 38: //up arrow\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );\n return false;\n case 40: //down arrow\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );\n return false;\n case 37: //left arrow\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );\n return false;\n case 39: //right arrow\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );\n return false;\n default:\n //console.log( 'navigator keycode %s', event.keyCode );\n return true;\n }\n } else {\n return true;\n }\n}\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onKeyPress( event ) {\n //console.log( event.keyCode );\n\n if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) {\n switch ( event.keyCode ) {\n case 61: //=|+\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );\n return false;\n case 45: //-|_\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );\n return false;\n case 48: //0|)\n case 119: //w\n case 87: //W\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );\n return false;\n case 115: //s\n case 83: //S\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );\n return false;\n case 97: //a\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );\n return false;\n case 100: //d\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );\n return false;\n default:\n //console.log( 'navigator keycode %s', event.keyCode );\n return true;\n }\n } else {\n return true;\n }\n}\n\n}(OpenSeadragon));\n","/*\n * OpenSeadragon - DisplayRect\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class DisplayRect\n * @classdesc A display rectangle is very similar to {@link OpenSeadragon.Rect} but adds two\n * fields, 'minLevel' and 'maxLevel' which denote the supported zoom levels\n * for this rectangle.\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.Rect\n * @param {Number} x The vector component 'x'.\n * @param {Number} y The vector component 'y'.\n * @param {Number} width The vector component 'height'.\n * @param {Number} height The vector component 'width'.\n * @param {Number} minLevel The lowest zoom level supported.\n * @param {Number} maxLevel The highest zoom level supported.\n */\n$.DisplayRect = function( x, y, width, height, minLevel, maxLevel ) {\n $.Rect.apply( this, [ x, y, width, height ] );\n\n /**\n * The lowest zoom level supported.\n * @member {Number} minLevel\n * @memberof OpenSeadragon.DisplayRect#\n */\n this.minLevel = minLevel;\n /**\n * The highest zoom level supported.\n * @member {Number} maxLevel\n * @memberof OpenSeadragon.DisplayRect#\n */\n this.maxLevel = maxLevel;\n};\n\n$.extend( $.DisplayRect.prototype, $.Rect.prototype );\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - Spring\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class Spring\n * @memberof OpenSeadragon\n * @param {Object} options - Spring configuration settings.\n * @param {Number} options.springStiffness - Spring stiffness. Must be greater than zero.\n * The closer to zero, the closer to linear animation.\n * @param {Number} options.animationTime - Animation duration per spring, in seconds.\n * Must be zero or greater.\n * @param {Number} [options.initial=0] - Initial value of spring.\n * @param {Boolean} [options.exponential=false] - Whether this spring represents\n * an exponential scale (such as zoom) and should be animated accordingly. Note that\n * exponential springs must have non-zero values.\n */\n$.Spring = function( options ) {\n var args = arguments;\n\n if( typeof( options ) != 'object' ){\n //allows backward compatible use of ( initialValue, config ) as\n //constructor parameters\n options = {\n initial: args.length && typeof ( args[ 0 ] ) == \"number\" ?\n args[ 0 ] :\n undefined,\n /**\n * Spring stiffness.\n * @member {Number} springStiffness\n * @memberof OpenSeadragon.Spring#\n */\n springStiffness: args.length > 1 ?\n args[ 1 ].springStiffness :\n 5.0,\n /**\n * Animation duration per spring.\n * @member {Number} animationTime\n * @memberof OpenSeadragon.Spring#\n */\n animationTime: args.length > 1 ?\n args[ 1 ].animationTime :\n 1.5\n };\n }\n\n $.console.assert(typeof options.springStiffness === \"number\" && options.springStiffness !== 0,\n \"[OpenSeadragon.Spring] options.springStiffness must be a non-zero number\");\n\n $.console.assert(typeof options.animationTime === \"number\" && options.animationTime >= 0,\n \"[OpenSeadragon.Spring] options.animationTime must be a number greater than or equal to 0\");\n\n if (options.exponential) {\n this._exponential = true;\n delete options.exponential;\n }\n\n $.extend( true, this, options);\n\n /**\n * @member {Object} current\n * @memberof OpenSeadragon.Spring#\n * @property {Number} value\n * @property {Number} time\n */\n this.current = {\n value: typeof ( this.initial ) == \"number\" ?\n this.initial :\n (this._exponential ? 0 : 1),\n time: $.now() // always work in milliseconds\n };\n\n $.console.assert(!this._exponential || this.current.value !== 0,\n \"[OpenSeadragon.Spring] value must be non-zero for exponential springs\");\n\n /**\n * @member {Object} start\n * @memberof OpenSeadragon.Spring#\n * @property {Number} value\n * @property {Number} time\n */\n this.start = {\n value: this.current.value,\n time: this.current.time\n };\n\n /**\n * @member {Object} target\n * @memberof OpenSeadragon.Spring#\n * @property {Number} value\n * @property {Number} time\n */\n this.target = {\n value: this.current.value,\n time: this.current.time\n };\n\n if (this._exponential) {\n this.start._logValue = Math.log(this.start.value);\n this.target._logValue = Math.log(this.target.value);\n this.current._logValue = Math.log(this.current.value);\n }\n};\n\n/** @lends OpenSeadragon.Spring.prototype */\n$.Spring.prototype = {\n\n /**\n * @function\n * @param {Number} target\n */\n resetTo: function( target ) {\n $.console.assert(!this._exponential || target !== 0,\n \"[OpenSeadragon.Spring.resetTo] target must be non-zero for exponential springs\");\n\n this.start.value = this.target.value = this.current.value = target;\n this.start.time = this.target.time = this.current.time = $.now();\n\n if (this._exponential) {\n this.start._logValue = Math.log(this.start.value);\n this.target._logValue = Math.log(this.target.value);\n this.current._logValue = Math.log(this.current.value);\n }\n },\n\n /**\n * @function\n * @param {Number} target\n */\n springTo: function( target ) {\n $.console.assert(!this._exponential || target !== 0,\n \"[OpenSeadragon.Spring.springTo] target must be non-zero for exponential springs\");\n\n this.start.value = this.current.value;\n this.start.time = this.current.time;\n this.target.value = target;\n this.target.time = this.start.time + 1000 * this.animationTime;\n\n if (this._exponential) {\n this.start._logValue = Math.log(this.start.value);\n this.target._logValue = Math.log(this.target.value);\n }\n },\n\n /**\n * @function\n * @param {Number} delta\n */\n shiftBy: function( delta ) {\n this.start.value += delta;\n this.target.value += delta;\n\n if (this._exponential) {\n $.console.assert(this.target.value !== 0 && this.start.value !== 0,\n \"[OpenSeadragon.Spring.shiftBy] spring value must be non-zero for exponential springs\");\n\n this.start._logValue = Math.log(this.start.value);\n this.target._logValue = Math.log(this.target.value);\n }\n },\n\n setExponential: function(value) {\n this._exponential = value;\n\n if (this._exponential) {\n $.console.assert(this.current.value !== 0 && this.target.value !== 0 && this.start.value !== 0,\n \"[OpenSeadragon.Spring.setExponential] spring value must be non-zero for exponential springs\");\n\n this.start._logValue = Math.log(this.start.value);\n this.target._logValue = Math.log(this.target.value);\n this.current._logValue = Math.log(this.current.value);\n }\n },\n\n /**\n * @function\n * @returns true if the value got updated, false otherwise\n */\n update: function() {\n this.current.time = $.now();\n\n var startValue, targetValue;\n if (this._exponential) {\n startValue = this.start._logValue;\n targetValue = this.target._logValue;\n } else {\n startValue = this.start.value;\n targetValue = this.target.value;\n }\n\n var currentValue = (this.current.time >= this.target.time) ?\n targetValue :\n startValue +\n ( targetValue - startValue ) *\n transform(\n this.springStiffness,\n ( this.current.time - this.start.time ) /\n ( this.target.time - this.start.time )\n );\n\n var oldValue = this.current.value;\n if (this._exponential) {\n this.current.value = Math.exp(currentValue);\n } else {\n this.current.value = currentValue;\n }\n\n return oldValue != this.current.value;\n },\n\n /**\n * Returns whether the spring is at the target value\n * @function\n * @returns {Boolean} True if at target value, false otherwise\n */\n isAtTargetValue: function() {\n return this.current.value === this.target.value;\n }\n};\n\n/**\n * @private\n */\nfunction transform( stiffness, x ) {\n return ( 1.0 - Math.exp( stiffness * -x ) ) /\n ( 1.0 - Math.exp( -stiffness ) );\n}\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - ImageLoader\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function($){\n\n/**\n * @private\n * @class ImageJob\n * @classdesc Handles downloading of a single image.\n * @param {Object} options - Options for this ImageJob.\n * @param {String} [options.src] - URL of image to download.\n * @param {String} [options.loadWithAjax] - Whether to load this image with AJAX.\n * @param {String} [options.ajaxHeaders] - Headers to add to the image request if using AJAX.\n * @param {String} [options.crossOriginPolicy] - CORS policy to use for downloads\n * @param {Function} [options.callback] - Called once image has been downloaded.\n * @param {Function} [options.abort] - Called when this image job is aborted.\n * @param {Number} [options.timeout] - The max number of milliseconds that this image job may take to complete.\n */\nfunction ImageJob (options) {\n\n $.extend(true, this, {\n timeout: $.DEFAULT_SETTINGS.timeout,\n jobId: null\n }, options);\n\n /**\n * Image object which will contain downloaded image.\n * @member {Image} image\n * @memberof OpenSeadragon.ImageJob#\n */\n this.image = null;\n}\n\nImageJob.prototype = {\n errorMsg: null,\n\n /**\n * Starts the image job.\n * @method\n */\n start: function(){\n var self = this;\n var selfAbort = this.abort;\n\n this.image = new Image();\n\n this.image.onload = function(){\n self.finish(true);\n };\n this.image.onabort = this.image.onerror = function() {\n self.errorMsg = \"Image load aborted\";\n self.finish(false);\n };\n\n this.jobId = window.setTimeout(function(){\n self.errorMsg = \"Image load exceeded timeout\";\n self.finish(false);\n }, this.timeout);\n\n // Load the tile with an AJAX request if the loadWithAjax option is\n // set. Otherwise load the image by setting the source proprety of the image object.\n if (this.loadWithAjax) {\n this.request = $.makeAjaxRequest({\n url: this.src,\n withCredentials: this.ajaxWithCredentials,\n headers: this.ajaxHeaders,\n responseType: \"arraybuffer\",\n success: function(request) {\n var blb;\n // Make the raw data into a blob.\n // BlobBuilder fallback adapted from\n // http://stackoverflow.com/questions/15293694/blob-constructor-browser-compatibility\n try {\n blb = new window.Blob([request.response]);\n } catch (e) {\n var BlobBuilder = (\n window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder\n );\n if (e.name === 'TypeError' && BlobBuilder) {\n var bb = new BlobBuilder();\n bb.append(request.response);\n blb = bb.getBlob();\n }\n }\n // If the blob is empty for some reason consider the image load a failure.\n if (blb.size === 0) {\n self.errorMsg = \"Empty image response.\";\n self.finish(false);\n }\n // Create a URL for the blob data and make it the source of the image object.\n // This will still trigger Image.onload to indicate a successful tile load.\n var url = (window.URL || window.webkitURL).createObjectURL(blb);\n self.image.src = url;\n },\n error: function(request) {\n self.errorMsg = \"Image load aborted - XHR error\";\n self.finish(false);\n }\n });\n\n // Provide a function to properly abort the request.\n this.abort = function() {\n self.request.abort();\n\n // Call the existing abort function if available\n if (typeof selfAbort === \"function\") {\n selfAbort();\n }\n };\n } else {\n if (this.crossOriginPolicy !== false) {\n this.image.crossOrigin = this.crossOriginPolicy;\n }\n\n this.image.src = this.src;\n }\n },\n\n finish: function(successful) {\n this.image.onload = this.image.onerror = this.image.onabort = null;\n if (!successful) {\n this.image = null;\n }\n\n if (this.jobId) {\n window.clearTimeout(this.jobId);\n }\n\n this.callback(this);\n }\n\n};\n\n/**\n * @class ImageLoader\n * @memberof OpenSeadragon\n * @classdesc Handles downloading of a set of images using asynchronous queue pattern.\n * You generally won't have to interact with the ImageLoader directly.\n * @param {Object} options - Options for this ImageLoader.\n * @param {Number} [options.jobLimit] - The number of concurrent image requests. See imageLoaderLimit in {@link OpenSeadragon.Options} for details.\n * @param {Number} [options.timeout] - The max number of milliseconds that an image job may take to complete.\n */\n$.ImageLoader = function(options) {\n\n $.extend(true, this, {\n jobLimit: $.DEFAULT_SETTINGS.imageLoaderLimit,\n timeout: $.DEFAULT_SETTINGS.timeout,\n jobQueue: [],\n jobsInProgress: 0\n }, options);\n\n};\n\n/** @lends OpenSeadragon.ImageLoader.prototype */\n$.ImageLoader.prototype = {\n\n /**\n * Add an unloaded image to the loader queue.\n * @method\n * @param {Object} options - Options for this job.\n * @param {String} [options.src] - URL of image to download.\n * @param {String} [options.loadWithAjax] - Whether to load this image with AJAX.\n * @param {String} [options.ajaxHeaders] - Headers to add to the image request if using AJAX.\n * @param {String|Boolean} [options.crossOriginPolicy] - CORS policy to use for downloads\n * @param {Boolean} [options.ajaxWithCredentials] - Whether to set withCredentials on AJAX\n * requests.\n * @param {Function} [options.callback] - Called once image has been downloaded.\n * @param {Function} [options.abort] - Called when this image job is aborted.\n */\n addJob: function(options) {\n var _this = this,\n complete = function(job) {\n completeJob(_this, job, options.callback);\n },\n jobOptions = {\n src: options.src,\n loadWithAjax: options.loadWithAjax,\n ajaxHeaders: options.loadWithAjax ? options.ajaxHeaders : null,\n crossOriginPolicy: options.crossOriginPolicy,\n ajaxWithCredentials: options.ajaxWithCredentials,\n callback: complete,\n abort: options.abort,\n timeout: this.timeout\n },\n newJob = new ImageJob(jobOptions);\n\n if ( !this.jobLimit || this.jobsInProgress < this.jobLimit ) {\n newJob.start();\n this.jobsInProgress++;\n }\n else {\n this.jobQueue.push( newJob );\n }\n },\n\n /**\n * Clear any unstarted image loading jobs from the queue.\n * @method\n */\n clear: function() {\n for( var i = 0; i < this.jobQueue.length; i++ ) {\n var job = this.jobQueue[i];\n if ( typeof job.abort === \"function\" ) {\n job.abort();\n }\n }\n\n this.jobQueue = [];\n }\n};\n\n/**\n * Cleans up ImageJob once completed.\n * @method\n * @private\n * @param loader - ImageLoader used to start job.\n * @param job - The ImageJob that has completed.\n * @param callback - Called once cleanup is finished.\n */\nfunction completeJob(loader, job, callback) {\n var nextJob;\n\n loader.jobsInProgress--;\n\n if ((!loader.jobLimit || loader.jobsInProgress < loader.jobLimit) && loader.jobQueue.length > 0) {\n nextJob = loader.jobQueue.shift();\n nextJob.start();\n loader.jobsInProgress++;\n }\n\n callback(job.image, job.errorMsg, job.request);\n}\n\n}(OpenSeadragon));\n","/*\n * OpenSeadragon - Tile\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class Tile\n * @memberof OpenSeadragon\n * @param {Number} level The zoom level this tile belongs to.\n * @param {Number} x The vector component 'x'.\n * @param {Number} y The vector component 'y'.\n * @param {OpenSeadragon.Point} bounds Where this tile fits, in normalized\n * coordinates.\n * @param {Boolean} exists Is this tile a part of a sparse image? ( Also has\n * this tile failed to load? )\n * @param {String} url The URL of this tile's image.\n * @param {CanvasRenderingContext2D} context2D The context2D of this tile if it\n * is provided directly by the tile source.\n * @param {Boolean} loadWithAjax Whether this tile image should be loaded with an AJAX request .\n * @param {Object} ajaxHeaders The headers to send with this tile's AJAX request (if applicable).\n */\n$.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, ajaxHeaders) {\n /**\n * The zoom level this tile belongs to.\n * @member {Number} level\n * @memberof OpenSeadragon.Tile#\n */\n this.level = level;\n /**\n * The vector component 'x'.\n * @member {Number} x\n * @memberof OpenSeadragon.Tile#\n */\n this.x = x;\n /**\n * The vector component 'y'.\n * @member {Number} y\n * @memberof OpenSeadragon.Tile#\n */\n this.y = y;\n /**\n * Where this tile fits, in normalized coordinates\n * @member {OpenSeadragon.Rect} bounds\n * @memberof OpenSeadragon.Tile#\n */\n this.bounds = bounds;\n /**\n * Is this tile a part of a sparse image? Also has this tile failed to load?\n * @member {Boolean} exists\n * @memberof OpenSeadragon.Tile#\n */\n this.exists = exists;\n /**\n * The URL of this tile's image.\n * @member {String} url\n * @memberof OpenSeadragon.Tile#\n */\n this.url = url;\n /**\n * The context2D of this tile if it is provided directly by the tile source.\n * @member {CanvasRenderingContext2D} context2D\n * @memberOf OpenSeadragon.Tile#\n */\n this.context2D = context2D;\n /**\n * Whether to load this tile's image with an AJAX request.\n * @member {Boolean} loadWithAjax\n * @memberof OpenSeadragon.Tile#\n */\n this.loadWithAjax = loadWithAjax;\n /**\n * The headers to be used in requesting this tile's image.\n * Only used if loadWithAjax is set to true.\n * @member {Object} ajaxHeaders\n * @memberof OpenSeadragon.Tile#\n */\n this.ajaxHeaders = ajaxHeaders;\n /**\n * The unique cache key for this tile.\n * @member {String} cacheKey\n * @memberof OpenSeadragon.Tile#\n */\n if (this.ajaxHeaders) {\n this.cacheKey = this.url + \"+\" + JSON.stringify(this.ajaxHeaders);\n } else {\n this.cacheKey = this.url;\n }\n /**\n * Is this tile loaded?\n * @member {Boolean} loaded\n * @memberof OpenSeadragon.Tile#\n */\n this.loaded = false;\n /**\n * Is this tile loading?\n * @member {Boolean} loading\n * @memberof OpenSeadragon.Tile#\n */\n this.loading = false;\n\n /**\n * The HTML div element for this tile\n * @member {Element} element\n * @memberof OpenSeadragon.Tile#\n */\n this.element = null;\n /**\n * The HTML img element for this tile.\n * @member {Element} imgElement\n * @memberof OpenSeadragon.Tile#\n */\n this.imgElement = null;\n /**\n * The Image object for this tile.\n * @member {Object} image\n * @memberof OpenSeadragon.Tile#\n */\n this.image = null;\n\n /**\n * The alias of this.element.style.\n * @member {String} style\n * @memberof OpenSeadragon.Tile#\n */\n this.style = null;\n /**\n * This tile's position on screen, in pixels.\n * @member {OpenSeadragon.Point} position\n * @memberof OpenSeadragon.Tile#\n */\n this.position = null;\n /**\n * This tile's size on screen, in pixels.\n * @member {OpenSeadragon.Point} size\n * @memberof OpenSeadragon.Tile#\n */\n this.size = null;\n /**\n * The start time of this tile's blending.\n * @member {Number} blendStart\n * @memberof OpenSeadragon.Tile#\n */\n this.blendStart = null;\n /**\n * The current opacity this tile should be.\n * @member {Number} opacity\n * @memberof OpenSeadragon.Tile#\n */\n this.opacity = null;\n /**\n * The squared distance of this tile to the viewport center.\n * Use for comparing tiles.\n * @private\n * @member {Number} squaredDistance\n * @memberof OpenSeadragon.Tile#\n */\n this.squaredDistance = null;\n /**\n * The visibility score of this tile.\n * @member {Number} visibility\n * @memberof OpenSeadragon.Tile#\n */\n this.visibility = null;\n\n /**\n * Whether this tile is currently being drawn.\n * @member {Boolean} beingDrawn\n * @memberof OpenSeadragon.Tile#\n */\n this.beingDrawn = false;\n\n /**\n * Timestamp the tile was last touched.\n * @member {Number} lastTouchTime\n * @memberof OpenSeadragon.Tile#\n */\n this.lastTouchTime = 0;\n\n /**\n * Whether this tile is in the right-most column for its level.\n * @member {Boolean} isRightMost\n * @memberof OpenSeadragon.Tile#\n */\n this.isRightMost = false;\n\n /**\n * Whether this tile is in the bottom-most row for its level.\n * @member {Boolean} isBottomMost\n * @memberof OpenSeadragon.Tile#\n */\n this.isBottomMost = false;\n};\n\n/** @lends OpenSeadragon.Tile.prototype */\n$.Tile.prototype = {\n\n /**\n * Provides a string representation of this tiles level and (x,y)\n * components.\n * @function\n * @returns {String}\n */\n toString: function() {\n return this.level + \"/\" + this.x + \"_\" + this.y;\n },\n\n // private\n _hasTransparencyChannel: function() {\n return !!this.context2D || this.url.match('.png');\n },\n\n /**\n * Renders the tile in an html container.\n * @function\n * @param {Element} container\n */\n drawHTML: function( container ) {\n if (!this.cacheImageRecord) {\n $.console.warn(\n '[Tile.drawHTML] attempting to draw tile %s when it\\'s not cached',\n this.toString());\n return;\n }\n\n if ( !this.loaded ) {\n $.console.warn(\n \"Attempting to draw tile %s when it's not yet loaded.\",\n this.toString()\n );\n return;\n }\n\n //EXPERIMENTAL - trying to figure out how to scale the container\n // content during animation of the container size.\n\n if ( !this.element ) {\n this.element = $.makeNeutralElement( \"div\" );\n this.imgElement = this.cacheImageRecord.getImage().cloneNode();\n this.imgElement.style.msInterpolationMode = \"nearest-neighbor\";\n this.imgElement.style.width = \"100%\";\n this.imgElement.style.height = \"100%\";\n\n this.style = this.element.style;\n this.style.position = \"absolute\";\n }\n if ( this.element.parentNode != container ) {\n container.appendChild( this.element );\n }\n if ( this.imgElement.parentNode != this.element ) {\n this.element.appendChild( this.imgElement );\n }\n\n this.style.top = this.position.y + \"px\";\n this.style.left = this.position.x + \"px\";\n this.style.height = this.size.y + \"px\";\n this.style.width = this.size.x + \"px\";\n\n $.setElementOpacity( this.element, this.opacity );\n },\n\n /**\n * Renders the tile in a canvas-based context.\n * @function\n * @param {Canvas} context\n * @param {Function} drawingHandler - Method for firing the drawing event.\n * drawingHandler({context, tile, rendered})\n * where rendered is the context with the pre-drawn image.\n * @param {Number} [scale=1] - Apply a scale to position and size\n * @param {OpenSeadragon.Point} [translate] - A translation vector\n */\n drawCanvas: function( context, drawingHandler, scale, translate ) {\n\n var position = this.position.times($.pixelDensityRatio),\n size = this.size.times($.pixelDensityRatio),\n rendered;\n\n if (!this.context2D && !this.cacheImageRecord) {\n $.console.warn(\n '[Tile.drawCanvas] attempting to draw tile %s when it\\'s not cached',\n this.toString());\n return;\n }\n\n rendered = this.context2D || this.cacheImageRecord.getRenderedContext();\n\n if ( !this.loaded || !rendered ){\n $.console.warn(\n \"Attempting to draw tile %s when it's not yet loaded.\",\n this.toString()\n );\n\n return;\n }\n\n context.save();\n\n context.globalAlpha = this.opacity;\n\n if (typeof scale === 'number' && scale !== 1) {\n // draw tile at a different scale\n position = position.times(scale);\n size = size.times(scale);\n }\n\n if (translate instanceof $.Point) {\n // shift tile position slightly\n position = position.plus(translate);\n }\n\n //if we are supposed to be rendering fully opaque rectangle,\n //ie its done fading or fading is turned off, and if we are drawing\n //an image with an alpha channel, then the only way\n //to avoid seeing the tile underneath is to clear the rectangle\n if (context.globalAlpha === 1 && this._hasTransparencyChannel()) {\n //clearing only the inside of the rectangle occupied\n //by the png prevents edge flikering\n context.clearRect(\n position.x + 1,\n position.y + 1,\n size.x - 2,\n size.y - 2\n );\n }\n\n // This gives the application a chance to make image manipulation\n // changes as we are rendering the image\n drawingHandler({context: context, tile: this, rendered: rendered});\n\n context.drawImage(\n rendered.canvas,\n 0,\n 0,\n rendered.canvas.width,\n rendered.canvas.height,\n position.x,\n position.y,\n size.x,\n size.y\n );\n\n context.restore();\n },\n\n /**\n * Get the ratio between current and original size.\n * @function\n * @return {Float}\n */\n getScaleForEdgeSmoothing: function() {\n var context;\n if (this.cacheImageRecord) {\n context = this.cacheImageRecord.getRenderedContext();\n } else if (this.context2D) {\n context = this.context2D;\n } else {\n $.console.warn(\n '[Tile.drawCanvas] attempting to get tile scale %s when tile\\'s not cached',\n this.toString());\n return 1;\n }\n return context.canvas.width / (this.size.x * $.pixelDensityRatio);\n },\n\n /**\n * Get a translation vector that when applied to the tile position produces integer coordinates.\n * Needed to avoid swimming and twitching.\n * @function\n * @param {Number} [scale=1] - Scale to be applied to position.\n * @return {OpenSeadragon.Point}\n */\n getTranslationForEdgeSmoothing: function(scale, canvasSize, sketchCanvasSize) {\n // The translation vector must have positive values, otherwise the image goes a bit off\n // the sketch canvas to the top and left and we must use negative coordinates to repaint it\n // to the main canvas. In that case, some browsers throw:\n // INDEX_SIZE_ERR: DOM Exception 1: Index or size was negative, or greater than the allowed value.\n var x = Math.max(1, Math.ceil((sketchCanvasSize.x - canvasSize.x) / 2));\n var y = Math.max(1, Math.ceil((sketchCanvasSize.y - canvasSize.y) / 2));\n return new $.Point(x, y).minus(\n this.position\n .times($.pixelDensityRatio)\n .times(scale || 1)\n .apply(function(x) {\n return x % 1;\n })\n );\n },\n\n /**\n * Removes tile from its container.\n * @function\n */\n unload: function() {\n if ( this.imgElement && this.imgElement.parentNode ) {\n this.imgElement.parentNode.removeChild( this.imgElement );\n }\n if ( this.element && this.element.parentNode ) {\n this.element.parentNode.removeChild( this.element );\n }\n\n this.element = null;\n this.imgElement = null;\n this.loaded = false;\n this.loading = false;\n }\n};\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - Overlay\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function($) {\n\n /**\n * An enumeration of positions that an overlay may be assigned relative to\n * the viewport.\n * It is identical to OpenSeadragon.Placement but is kept for backward\n * compatibility.\n * @member OverlayPlacement\n * @memberof OpenSeadragon\n * @see OpenSeadragon.Placement\n * @static\n * @readonly\n * @type {Object}\n * @property {Number} CENTER\n * @property {Number} TOP_LEFT\n * @property {Number} TOP\n * @property {Number} TOP_RIGHT\n * @property {Number} RIGHT\n * @property {Number} BOTTOM_RIGHT\n * @property {Number} BOTTOM\n * @property {Number} BOTTOM_LEFT\n * @property {Number} LEFT\n */\n $.OverlayPlacement = $.Placement;\n\n /**\n * An enumeration of possible ways to handle overlays rotation\n * @member OverlayRotationMode\n * @memberOf OpenSeadragon\n * @static\n * @readonly\n * @property {Number} NO_ROTATION The overlay ignore the viewport rotation.\n * @property {Number} EXACT The overlay use CSS 3 transforms to rotate with\n * the viewport. If the overlay contains text, it will get rotated as well.\n * @property {Number} BOUNDING_BOX The overlay adjusts for rotation by\n * taking the size of the bounding box of the rotated bounds.\n * Only valid for overlays with Rect location and scalable in both directions.\n */\n $.OverlayRotationMode = $.freezeObject({\n NO_ROTATION: 1,\n EXACT: 2,\n BOUNDING_BOX: 3\n });\n\n /**\n * @class Overlay\n * @classdesc Provides a way to float an HTML element on top of the viewer element.\n *\n * @memberof OpenSeadragon\n * @param {Object} options\n * @param {Element} options.element\n * @param {OpenSeadragon.Point|OpenSeadragon.Rect} options.location - The\n * location of the overlay on the image. If a {@link OpenSeadragon.Point}\n * is specified, the overlay will be located at this location with respect\n * to the placement option. If a {@link OpenSeadragon.Rect} is specified,\n * the overlay will be placed at this location with the corresponding width\n * and height and placement TOP_LEFT.\n * @param {OpenSeadragon.Placement} [options.placement=OpenSeadragon.Placement.TOP_LEFT]\n * Defines what part of the overlay should be at the specified options.location\n * @param {OpenSeadragon.Overlay.OnDrawCallback} [options.onDraw]\n * @param {Boolean} [options.checkResize=true] Set to false to avoid to\n * check the size of the overlay everytime it is drawn in the directions\n * which are not scaled. It will improve performances but will cause a\n * misalignment if the overlay size changes.\n * @param {Number} [options.width] The width of the overlay in viewport\n * coordinates. If specified, the width of the overlay will be adjusted when\n * the zoom changes.\n * @param {Number} [options.height] The height of the overlay in viewport\n * coordinates. If specified, the height of the overlay will be adjusted when\n * the zoom changes.\n * @param {Boolean} [options.rotationMode=OpenSeadragon.OverlayRotationMode.EXACT]\n * How to handle the rotation of the viewport.\n */\n $.Overlay = function(element, location, placement) {\n\n /**\n * onDraw callback signature used by {@link OpenSeadragon.Overlay}.\n *\n * @callback OnDrawCallback\n * @memberof OpenSeadragon.Overlay\n * @param {OpenSeadragon.Point} position\n * @param {OpenSeadragon.Point} size\n * @param {Element} element\n */\n\n var options;\n if ($.isPlainObject(element)) {\n options = element;\n } else {\n options = {\n element: element,\n location: location,\n placement: placement\n };\n }\n\n this.element = options.element;\n this.style = options.element.style;\n this._init(options);\n };\n\n /** @lends OpenSeadragon.Overlay.prototype */\n $.Overlay.prototype = {\n\n // private\n _init: function(options) {\n this.location = options.location;\n this.placement = options.placement === undefined ?\n $.Placement.TOP_LEFT : options.placement;\n this.onDraw = options.onDraw;\n this.checkResize = options.checkResize === undefined ?\n true : options.checkResize;\n\n // When this.width is not null, the overlay get scaled horizontally\n this.width = options.width === undefined ? null : options.width;\n\n // When this.height is not null, the overlay get scaled vertically\n this.height = options.height === undefined ? null : options.height;\n\n this.rotationMode = options.rotationMode || $.OverlayRotationMode.EXACT;\n\n // Having a rect as location is a syntactic sugar\n if (this.location instanceof $.Rect) {\n this.width = this.location.width;\n this.height = this.location.height;\n this.location = this.location.getTopLeft();\n this.placement = $.Placement.TOP_LEFT;\n }\n\n // Deprecated properties kept for backward compatibility.\n this.scales = this.width !== null && this.height !== null;\n this.bounds = new $.Rect(\n this.location.x, this.location.y, this.width, this.height);\n this.position = this.location;\n },\n\n /**\n * Internal function to adjust the position of an overlay\n * depending on it size and placement.\n * @function\n * @param {OpenSeadragon.Point} position\n * @param {OpenSeadragon.Point} size\n */\n adjust: function(position, size) {\n var properties = $.Placement.properties[this.placement];\n if (!properties) {\n return;\n }\n if (properties.isHorizontallyCentered) {\n position.x -= size.x / 2;\n } else if (properties.isRight) {\n position.x -= size.x;\n }\n if (properties.isVerticallyCentered) {\n position.y -= size.y / 2;\n } else if (properties.isBottom) {\n position.y -= size.y;\n }\n },\n\n /**\n * @function\n */\n destroy: function() {\n var element = this.element;\n var style = this.style;\n\n if (element.parentNode) {\n element.parentNode.removeChild(element);\n //this should allow us to preserve overlays when required between\n //pages\n if (element.prevElementParent) {\n style.display = 'none';\n //element.prevElementParent.insertBefore(\n // element,\n // element.prevNextSibling\n //);\n document.body.appendChild(element);\n }\n }\n\n // clear the onDraw callback\n this.onDraw = null;\n\n style.top = \"\";\n style.left = \"\";\n style.position = \"\";\n\n if (this.width !== null) {\n style.width = \"\";\n }\n if (this.height !== null) {\n style.height = \"\";\n }\n var transformOriginProp = $.getCssPropertyWithVendorPrefix(\n 'transformOrigin');\n var transformProp = $.getCssPropertyWithVendorPrefix(\n 'transform');\n if (transformOriginProp && transformProp) {\n style[transformOriginProp] = \"\";\n style[transformProp] = \"\";\n }\n },\n\n /**\n * @function\n * @param {Element} container\n */\n drawHTML: function(container, viewport) {\n var element = this.element;\n if (element.parentNode !== container) {\n //save the source parent for later if we need it\n element.prevElementParent = element.parentNode;\n element.prevNextSibling = element.nextSibling;\n container.appendChild(element);\n\n // have to set position before calculating size, fix #1116\n this.style.position = \"absolute\";\n // this.size is used by overlays which don't get scaled in at\n // least one direction when this.checkResize is set to false.\n this.size = $.getElementSize(element);\n }\n\n var positionAndSize = this._getOverlayPositionAndSize(viewport);\n\n var position = positionAndSize.position;\n var size = this.size = positionAndSize.size;\n var rotate = positionAndSize.rotate;\n\n // call the onDraw callback if it exists to allow one to overwrite\n // the drawing/positioning/sizing of the overlay\n if (this.onDraw) {\n this.onDraw(position, size, this.element);\n } else {\n var style = this.style;\n style.left = position.x + \"px\";\n style.top = position.y + \"px\";\n if (this.width !== null) {\n style.width = size.x + \"px\";\n }\n if (this.height !== null) {\n style.height = size.y + \"px\";\n }\n var transformOriginProp = $.getCssPropertyWithVendorPrefix(\n 'transformOrigin');\n var transformProp = $.getCssPropertyWithVendorPrefix(\n 'transform');\n if (transformOriginProp && transformProp) {\n if (rotate) {\n style[transformOriginProp] = this._getTransformOrigin();\n style[transformProp] = \"rotate(\" + rotate + \"deg)\";\n } else {\n style[transformOriginProp] = \"\";\n style[transformProp] = \"\";\n }\n }\n\n if (style.display !== 'none') {\n style.display = 'block';\n }\n }\n },\n\n // private\n _getOverlayPositionAndSize: function(viewport) {\n var position = viewport.pixelFromPoint(this.location, true);\n var size = this._getSizeInPixels(viewport);\n this.adjust(position, size);\n\n var rotate = 0;\n if (viewport.degrees &&\n this.rotationMode !== $.OverlayRotationMode.NO_ROTATION) {\n // BOUNDING_BOX is only valid if both directions get scaled.\n // Get replaced by EXACT otherwise.\n if (this.rotationMode === $.OverlayRotationMode.BOUNDING_BOX &&\n this.width !== null && this.height !== null) {\n var rect = new $.Rect(position.x, position.y, size.x, size.y);\n var boundingBox = this._getBoundingBox(rect, viewport.degrees);\n position = boundingBox.getTopLeft();\n size = boundingBox.getSize();\n } else {\n rotate = viewport.degrees;\n }\n }\n\n return {\n position: position,\n size: size,\n rotate: rotate\n };\n },\n\n // private\n _getSizeInPixels: function(viewport) {\n var width = this.size.x;\n var height = this.size.y;\n if (this.width !== null || this.height !== null) {\n var scaledSize = viewport.deltaPixelsFromPointsNoRotate(\n new $.Point(this.width || 0, this.height || 0), true);\n if (this.width !== null) {\n width = scaledSize.x;\n }\n if (this.height !== null) {\n height = scaledSize.y;\n }\n }\n if (this.checkResize &&\n (this.width === null || this.height === null)) {\n var eltSize = this.size = $.getElementSize(this.element);\n if (this.width === null) {\n width = eltSize.x;\n }\n if (this.height === null) {\n height = eltSize.y;\n }\n }\n return new $.Point(width, height);\n },\n\n // private\n _getBoundingBox: function(rect, degrees) {\n var refPoint = this._getPlacementPoint(rect);\n return rect.rotate(degrees, refPoint).getBoundingBox();\n },\n\n // private\n _getPlacementPoint: function(rect) {\n var result = new $.Point(rect.x, rect.y);\n var properties = $.Placement.properties[this.placement];\n if (properties) {\n if (properties.isHorizontallyCentered) {\n result.x += rect.width / 2;\n } else if (properties.isRight) {\n result.x += rect.width;\n }\n if (properties.isVerticallyCentered) {\n result.y += rect.height / 2;\n } else if (properties.isBottom) {\n result.y += rect.height;\n }\n }\n return result;\n },\n\n // private\n _getTransformOrigin: function() {\n var result = \"\";\n var properties = $.Placement.properties[this.placement];\n if (!properties) {\n return result;\n }\n if (properties.isLeft) {\n result = \"left\";\n } else if (properties.isRight) {\n result = \"right\";\n }\n if (properties.isTop) {\n result += \" top\";\n } else if (properties.isBottom) {\n result += \" bottom\";\n }\n return result;\n },\n\n /**\n * Changes the overlay settings.\n * @function\n * @param {OpenSeadragon.Point|OpenSeadragon.Rect|Object} location\n * If an object is specified, the options are the same than the constructor\n * except for the element which can not be changed.\n * @param {OpenSeadragon.Placement} placement\n */\n update: function(location, placement) {\n var options = $.isPlainObject(location) ? location : {\n location: location,\n placement: placement\n };\n this._init({\n location: options.location || this.location,\n placement: options.placement !== undefined ?\n options.placement : this.placement,\n onDraw: options.onDraw || this.onDraw,\n checkResize: options.checkResize || this.checkResize,\n width: options.width !== undefined ? options.width : this.width,\n height: options.height !== undefined ? options.height : this.height,\n rotationMode: options.rotationMode || this.rotationMode\n });\n },\n\n /**\n * Returns the current bounds of the overlay in viewport coordinates\n * @function\n * @param {OpenSeadragon.Viewport} viewport the viewport\n * @returns {OpenSeadragon.Rect} overlay bounds\n */\n getBounds: function(viewport) {\n $.console.assert(viewport,\n 'A viewport must now be passed to Overlay.getBounds.');\n var width = this.width;\n var height = this.height;\n if (width === null || height === null) {\n var size = viewport.deltaPointsFromPixelsNoRotate(this.size, true);\n if (width === null) {\n width = size.x;\n }\n if (height === null) {\n height = size.y;\n }\n }\n var location = this.location.clone();\n this.adjust(location, new $.Point(width, height));\n return this._adjustBoundsForRotation(\n viewport, new $.Rect(location.x, location.y, width, height));\n },\n\n // private\n _adjustBoundsForRotation: function(viewport, bounds) {\n if (!viewport ||\n viewport.degrees === 0 ||\n this.rotationMode === $.OverlayRotationMode.EXACT) {\n return bounds;\n }\n if (this.rotationMode === $.OverlayRotationMode.BOUNDING_BOX) {\n // If overlay not fully scalable, BOUNDING_BOX falls back to EXACT\n if (this.width === null || this.height === null) {\n return bounds;\n }\n // It is easier to just compute the position and size and\n // convert to viewport coordinates.\n var positionAndSize = this._getOverlayPositionAndSize(viewport);\n return viewport.viewerElementToViewportRectangle(new $.Rect(\n positionAndSize.position.x,\n positionAndSize.position.y,\n positionAndSize.size.x,\n positionAndSize.size.y));\n }\n\n // NO_ROTATION case\n return bounds.rotate(-viewport.degrees,\n this._getPlacementPoint(bounds));\n }\n };\n\n}(OpenSeadragon));\n","/*\n * OpenSeadragon - Drawer\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class Drawer\n * @memberof OpenSeadragon\n * @classdesc Handles rendering of tiles for an {@link OpenSeadragon.Viewer}.\n * @param {Object} options - Options for this Drawer.\n * @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this Drawer.\n * @param {OpenSeadragon.Viewport} options.viewport - Reference to Viewer viewport.\n * @param {Element} options.element - Parent element.\n * @param {Number} [options.debugGridColor] - See debugGridColor in {@link OpenSeadragon.Options} for details.\n */\n$.Drawer = function( options ) {\n\n $.console.assert( options.viewer, \"[Drawer] options.viewer is required\" );\n\n //backward compatibility for positional args while prefering more\n //idiomatic javascript options object as the only argument\n var args = arguments;\n\n if( !$.isPlainObject( options ) ){\n options = {\n source: args[ 0 ], // Reference to Viewer tile source.\n viewport: args[ 1 ], // Reference to Viewer viewport.\n element: args[ 2 ] // Parent element.\n };\n }\n\n $.console.assert( options.viewport, \"[Drawer] options.viewport is required\" );\n $.console.assert( options.element, \"[Drawer] options.element is required\" );\n\n if ( options.source ) {\n $.console.error( \"[Drawer] options.source is no longer accepted; use TiledImage instead\" );\n }\n\n this.viewer = options.viewer;\n this.viewport = options.viewport;\n this.debugGridColor = typeof options.debugGridColor === 'string' ? [options.debugGridColor] : options.debugGridColor || $.DEFAULT_SETTINGS.debugGridColor;\n if (options.opacity) {\n $.console.error( \"[Drawer] options.opacity is no longer accepted; set the opacity on the TiledImage instead\" );\n }\n\n this.useCanvas = $.supportsCanvas && ( this.viewer ? this.viewer.useCanvas : true );\n /**\n * The parent element of this Drawer instance, passed in when the Drawer was created.\n * The parent of {@link OpenSeadragon.Drawer#canvas}.\n * @member {Element} container\n * @memberof OpenSeadragon.Drawer#\n */\n this.container = $.getElement( options.element );\n /**\n * A <canvas> element if the browser supports them, otherwise a <div> element.\n * Child element of {@link OpenSeadragon.Drawer#container}.\n * @member {Element} canvas\n * @memberof OpenSeadragon.Drawer#\n */\n this.canvas = $.makeNeutralElement( this.useCanvas ? \"canvas\" : \"div\" );\n /**\n * 2d drawing context for {@link OpenSeadragon.Drawer#canvas} if it's a <canvas> element, otherwise null.\n * @member {Object} context\n * @memberof OpenSeadragon.Drawer#\n */\n this.context = this.useCanvas ? this.canvas.getContext( \"2d\" ) : null;\n\n /**\n * Sketch canvas used to temporarily draw tiles which cannot be drawn directly\n * to the main canvas due to opacity. Lazily initialized.\n */\n this.sketchCanvas = null;\n this.sketchContext = null;\n\n /**\n * @member {Element} element\n * @memberof OpenSeadragon.Drawer#\n * @deprecated Alias for {@link OpenSeadragon.Drawer#container}.\n */\n this.element = this.container;\n\n // We force our container to ltr because our drawing math doesn't work in rtl.\n // This issue only affects our canvas renderer, but we do it always for consistency.\n // Note that this means overlays you want to be rtl need to be explicitly set to rtl.\n this.container.dir = 'ltr';\n\n // check canvas available width and height, set canvas width and height such that the canvas backing store is set to the proper pixel density\n if (this.useCanvas) {\n var viewportSize = this._calculateCanvasSize();\n this.canvas.width = viewportSize.x;\n this.canvas.height = viewportSize.y;\n }\n\n this.canvas.style.width = \"100%\";\n this.canvas.style.height = \"100%\";\n this.canvas.style.position = \"absolute\";\n $.setElementOpacity( this.canvas, this.opacity, true );\n\n // explicit left-align\n this.container.style.textAlign = \"left\";\n this.container.appendChild( this.canvas );\n};\n\n/** @lends OpenSeadragon.Drawer.prototype */\n$.Drawer.prototype = {\n // deprecated\n addOverlay: function( element, location, placement, onDraw ) {\n $.console.error(\"drawer.addOverlay is deprecated. Use viewer.addOverlay instead.\");\n this.viewer.addOverlay( element, location, placement, onDraw );\n return this;\n },\n\n // deprecated\n updateOverlay: function( element, location, placement ) {\n $.console.error(\"drawer.updateOverlay is deprecated. Use viewer.updateOverlay instead.\");\n this.viewer.updateOverlay( element, location, placement );\n return this;\n },\n\n // deprecated\n removeOverlay: function( element ) {\n $.console.error(\"drawer.removeOverlay is deprecated. Use viewer.removeOverlay instead.\");\n this.viewer.removeOverlay( element );\n return this;\n },\n\n // deprecated\n clearOverlays: function() {\n $.console.error(\"drawer.clearOverlays is deprecated. Use viewer.clearOverlays instead.\");\n this.viewer.clearOverlays();\n return this;\n },\n\n /**\n * Set the opacity of the drawer.\n * @param {Number} opacity\n * @return {OpenSeadragon.Drawer} Chainable.\n */\n setOpacity: function( opacity ) {\n $.console.error(\"drawer.setOpacity is deprecated. Use tiledImage.setOpacity instead.\");\n var world = this.viewer.world;\n for (var i = 0; i < world.getItemCount(); i++) {\n world.getItemAt( i ).setOpacity( opacity );\n }\n return this;\n },\n\n /**\n * Get the opacity of the drawer.\n * @returns {Number}\n */\n getOpacity: function() {\n $.console.error(\"drawer.getOpacity is deprecated. Use tiledImage.getOpacity instead.\");\n var world = this.viewer.world;\n var maxOpacity = 0;\n for (var i = 0; i < world.getItemCount(); i++) {\n var opacity = world.getItemAt( i ).getOpacity();\n if ( opacity > maxOpacity ) {\n maxOpacity = opacity;\n }\n }\n return maxOpacity;\n },\n\n // deprecated\n needsUpdate: function() {\n $.console.error( \"[Drawer.needsUpdate] this function is deprecated. Use World.needsDraw instead.\" );\n return this.viewer.world.needsDraw();\n },\n\n // deprecated\n numTilesLoaded: function() {\n $.console.error( \"[Drawer.numTilesLoaded] this function is deprecated. Use TileCache.numTilesLoaded instead.\" );\n return this.viewer.tileCache.numTilesLoaded();\n },\n\n // deprecated\n reset: function() {\n $.console.error( \"[Drawer.reset] this function is deprecated. Use World.resetItems instead.\" );\n this.viewer.world.resetItems();\n return this;\n },\n\n // deprecated\n update: function() {\n $.console.error( \"[Drawer.update] this function is deprecated. Use Drawer.clear and World.draw instead.\" );\n this.clear();\n this.viewer.world.draw();\n return this;\n },\n\n /**\n * @return {Boolean} True if rotation is supported.\n */\n canRotate: function() {\n return this.useCanvas;\n },\n\n /**\n * Destroy the drawer (unload current loaded tiles)\n */\n destroy: function() {\n //force unloading of current canvas (1x1 will be gc later, trick not necessarily needed)\n this.canvas.width = 1;\n this.canvas.height = 1;\n this.sketchCanvas = null;\n this.sketchContext = null;\n },\n\n /**\n * Clears the Drawer so it's ready to draw another frame.\n */\n clear: function() {\n this.canvas.innerHTML = \"\";\n if ( this.useCanvas ) {\n var viewportSize = this._calculateCanvasSize();\n if( this.canvas.width != viewportSize.x ||\n this.canvas.height != viewportSize.y ) {\n this.canvas.width = viewportSize.x;\n this.canvas.height = viewportSize.y;\n if ( this.sketchCanvas !== null ) {\n var sketchCanvasSize = this._calculateSketchCanvasSize();\n this.sketchCanvas.width = sketchCanvasSize.x;\n this.sketchCanvas.height = sketchCanvasSize.y;\n }\n }\n this._clear();\n }\n },\n\n _clear: function (useSketch, bounds) {\n if (!this.useCanvas) {\n return;\n }\n var context = this._getContext(useSketch);\n if (bounds) {\n context.clearRect(bounds.x, bounds.y, bounds.width, bounds.height);\n } else {\n var canvas = context.canvas;\n context.clearRect(0, 0, canvas.width, canvas.height);\n }\n },\n\n /**\n * Scale from OpenSeadragon viewer rectangle to drawer rectangle\n * (ignoring rotation)\n * @param {OpenSeadragon.Rect} rectangle - The rectangle in viewport coordinate system.\n * @return {OpenSeadragon.Rect} Rectangle in drawer coordinate system.\n */\n viewportToDrawerRectangle: function(rectangle) {\n var topLeft = this.viewport.pixelFromPointNoRotate(rectangle.getTopLeft(), true);\n var size = this.viewport.deltaPixelsFromPointsNoRotate(rectangle.getSize(), true);\n\n return new $.Rect(\n topLeft.x * $.pixelDensityRatio,\n topLeft.y * $.pixelDensityRatio,\n size.x * $.pixelDensityRatio,\n size.y * $.pixelDensityRatio\n );\n },\n\n /**\n * Draws the given tile.\n * @param {OpenSeadragon.Tile} tile - The tile to draw.\n * @param {Function} drawingHandler - Method for firing the drawing event if using canvas.\n * drawingHandler({context, tile, rendered})\n * @param {Boolean} useSketch - Whether to use the sketch canvas or not.\n * where rendered is the context with the pre-drawn image.\n * @param {Float} [scale=1] - Apply a scale to tile position and size. Defaults to 1.\n * @param {OpenSeadragon.Point} [translate] A translation vector to offset tile position\n */\n drawTile: function(tile, drawingHandler, useSketch, scale, translate) {\n $.console.assert(tile, '[Drawer.drawTile] tile is required');\n $.console.assert(drawingHandler, '[Drawer.drawTile] drawingHandler is required');\n\n if (this.useCanvas) {\n var context = this._getContext(useSketch);\n scale = scale || 1;\n tile.drawCanvas(context, drawingHandler, scale, translate);\n } else {\n tile.drawHTML( this.canvas );\n }\n },\n\n _getContext: function( useSketch ) {\n var context = this.context;\n if ( useSketch ) {\n if (this.sketchCanvas === null) {\n this.sketchCanvas = document.createElement( \"canvas\" );\n var sketchCanvasSize = this._calculateSketchCanvasSize();\n this.sketchCanvas.width = sketchCanvasSize.x;\n this.sketchCanvas.height = sketchCanvasSize.y;\n this.sketchContext = this.sketchCanvas.getContext( \"2d\" );\n\n // If the viewport is not currently rotated, the sketchCanvas\n // will have the same size as the main canvas. However, if\n // the viewport get rotated later on, we will need to resize it.\n if (this.viewport.getRotation() === 0) {\n var self = this;\n this.viewer.addHandler('rotate', function resizeSketchCanvas() {\n if (self.viewport.getRotation() === 0) {\n return;\n }\n self.viewer.removeHandler('rotate', resizeSketchCanvas);\n var sketchCanvasSize = self._calculateSketchCanvasSize();\n self.sketchCanvas.width = sketchCanvasSize.x;\n self.sketchCanvas.height = sketchCanvasSize.y;\n });\n }\n }\n context = this.sketchContext;\n }\n return context;\n },\n\n // private\n saveContext: function( useSketch ) {\n if (!this.useCanvas) {\n return;\n }\n\n this._getContext( useSketch ).save();\n },\n\n // private\n restoreContext: function( useSketch ) {\n if (!this.useCanvas) {\n return;\n }\n\n this._getContext( useSketch ).restore();\n },\n\n // private\n setClip: function(rect, useSketch) {\n if (!this.useCanvas) {\n return;\n }\n\n var context = this._getContext( useSketch );\n context.beginPath();\n context.rect(rect.x, rect.y, rect.width, rect.height);\n context.clip();\n },\n\n // private\n drawRectangle: function(rect, fillStyle, useSketch) {\n if (!this.useCanvas) {\n return;\n }\n\n var context = this._getContext( useSketch );\n context.save();\n context.fillStyle = fillStyle;\n context.fillRect(rect.x, rect.y, rect.width, rect.height);\n context.restore();\n },\n\n /**\n * Blends the sketch canvas in the main canvas.\n * @param {Object} options The options\n * @param {Float} options.opacity The opacity of the blending.\n * @param {Float} [options.scale=1] The scale at which tiles were drawn on\n * the sketch. Default is 1.\n * Use scale to draw at a lower scale and then enlarge onto the main canvas.\n * @param {OpenSeadragon.Point} [options.translate] A translation vector\n * that was used to draw the tiles\n * @param {String} [options.compositeOperation] - How the image is\n * composited onto other images; see compositeOperation in\n * {@link OpenSeadragon.Options} for possible values.\n * @param {OpenSeadragon.Rect} [options.bounds] The part of the sketch\n * canvas to blend in the main canvas. If specified, options.scale and\n * options.translate get ignored.\n */\n blendSketch: function(opacity, scale, translate, compositeOperation) {\n var options = opacity;\n if (!$.isPlainObject(options)) {\n options = {\n opacity: opacity,\n scale: scale,\n translate: translate,\n compositeOperation: compositeOperation\n };\n }\n if (!this.useCanvas || !this.sketchCanvas) {\n return;\n }\n opacity = options.opacity;\n compositeOperation = options.compositeOperation;\n var bounds = options.bounds;\n\n this.context.save();\n this.context.globalAlpha = opacity;\n if (compositeOperation) {\n this.context.globalCompositeOperation = compositeOperation;\n }\n if (bounds) {\n // Internet Explorer, Microsoft Edge, and Safari have problems\n // when you call context.drawImage with negative x or y\n // or x + width or y + height greater than the canvas width or height respectively.\n if (bounds.x < 0) {\n bounds.width += bounds.x;\n bounds.x = 0;\n }\n if (bounds.x + bounds.width > this.canvas.width) {\n bounds.width = this.canvas.width - bounds.x;\n }\n if (bounds.y < 0) {\n bounds.height += bounds.y;\n bounds.y = 0;\n }\n if (bounds.y + bounds.height > this.canvas.height) {\n bounds.height = this.canvas.height - bounds.y;\n }\n\n this.context.drawImage(\n this.sketchCanvas,\n bounds.x,\n bounds.y,\n bounds.width,\n bounds.height,\n bounds.x,\n bounds.y,\n bounds.width,\n bounds.height\n );\n } else {\n scale = options.scale || 1;\n translate = options.translate;\n var position = translate instanceof $.Point ?\n translate : new $.Point(0, 0);\n\n var widthExt = 0;\n var heightExt = 0;\n if (translate) {\n var widthDiff = this.sketchCanvas.width - this.canvas.width;\n var heightDiff = this.sketchCanvas.height - this.canvas.height;\n widthExt = Math.round(widthDiff / 2);\n heightExt = Math.round(heightDiff / 2);\n }\n this.context.drawImage(\n this.sketchCanvas,\n position.x - widthExt * scale,\n position.y - heightExt * scale,\n (this.canvas.width + 2 * widthExt) * scale,\n (this.canvas.height + 2 * heightExt) * scale,\n -widthExt,\n -heightExt,\n this.canvas.width + 2 * widthExt,\n this.canvas.height + 2 * heightExt\n );\n }\n this.context.restore();\n },\n\n // private\n drawDebugInfo: function(tile, count, i, tiledImage) {\n if ( !this.useCanvas ) {\n return;\n }\n\n var colorIndex = this.viewer.world.getIndexOfItem(tiledImage) % this.debugGridColor.length;\n var context = this.context;\n context.save();\n context.lineWidth = 2 * $.pixelDensityRatio;\n context.font = 'small-caps bold ' + (13 * $.pixelDensityRatio) + 'px arial';\n context.strokeStyle = this.debugGridColor[colorIndex];\n context.fillStyle = this.debugGridColor[colorIndex];\n\n if ( this.viewport.degrees !== 0 ) {\n this._offsetForRotation({degrees: this.viewport.degrees});\n }\n if (tiledImage.getRotation(true) % 360 !== 0) {\n this._offsetForRotation({\n degrees: tiledImage.getRotation(true),\n point: tiledImage.viewport.pixelFromPointNoRotate(\n tiledImage._getRotationPoint(true), true)\n });\n }\n\n context.strokeRect(\n tile.position.x * $.pixelDensityRatio,\n tile.position.y * $.pixelDensityRatio,\n tile.size.x * $.pixelDensityRatio,\n tile.size.y * $.pixelDensityRatio\n );\n\n var tileCenterX = (tile.position.x + (tile.size.x / 2)) * $.pixelDensityRatio;\n var tileCenterY = (tile.position.y + (tile.size.y / 2)) * $.pixelDensityRatio;\n\n // Rotate the text the right way around.\n context.translate( tileCenterX, tileCenterY );\n context.rotate( Math.PI / 180 * -this.viewport.degrees );\n context.translate( -tileCenterX, -tileCenterY );\n\n if( tile.x === 0 && tile.y === 0 ){\n context.fillText(\n \"Zoom: \" + this.viewport.getZoom(),\n tile.position.x * $.pixelDensityRatio,\n (tile.position.y - 30) * $.pixelDensityRatio\n );\n context.fillText(\n \"Pan: \" + this.viewport.getBounds().toString(),\n tile.position.x * $.pixelDensityRatio,\n (tile.position.y - 20) * $.pixelDensityRatio\n );\n }\n context.fillText(\n \"Level: \" + tile.level,\n (tile.position.x + 10) * $.pixelDensityRatio,\n (tile.position.y + 20) * $.pixelDensityRatio\n );\n context.fillText(\n \"Column: \" + tile.x,\n (tile.position.x + 10) * $.pixelDensityRatio,\n (tile.position.y + 30) * $.pixelDensityRatio\n );\n context.fillText(\n \"Row: \" + tile.y,\n (tile.position.x + 10) * $.pixelDensityRatio,\n (tile.position.y + 40) * $.pixelDensityRatio\n );\n context.fillText(\n \"Order: \" + i + \" of \" + count,\n (tile.position.x + 10) * $.pixelDensityRatio,\n (tile.position.y + 50) * $.pixelDensityRatio\n );\n context.fillText(\n \"Size: \" + tile.size.toString(),\n (tile.position.x + 10) * $.pixelDensityRatio,\n (tile.position.y + 60) * $.pixelDensityRatio\n );\n context.fillText(\n \"Position: \" + tile.position.toString(),\n (tile.position.x + 10) * $.pixelDensityRatio,\n (tile.position.y + 70) * $.pixelDensityRatio\n );\n\n if ( this.viewport.degrees !== 0 ) {\n this._restoreRotationChanges();\n }\n if (tiledImage.getRotation(true) % 360 !== 0) {\n this._restoreRotationChanges();\n }\n context.restore();\n },\n\n // private\n debugRect: function(rect) {\n if ( this.useCanvas ) {\n var context = this.context;\n context.save();\n context.lineWidth = 2 * $.pixelDensityRatio;\n context.strokeStyle = this.debugGridColor[0];\n context.fillStyle = this.debugGridColor[0];\n\n context.strokeRect(\n rect.x * $.pixelDensityRatio,\n rect.y * $.pixelDensityRatio,\n rect.width * $.pixelDensityRatio,\n rect.height * $.pixelDensityRatio\n );\n\n context.restore();\n }\n },\n\n /**\n * Get the canvas size\n * @param {Boolean} sketch If set to true return the size of the sketch canvas\n * @returns {OpenSeadragon.Point} The size of the canvas\n */\n getCanvasSize: function(sketch) {\n var canvas = this._getContext(sketch).canvas;\n return new $.Point(canvas.width, canvas.height);\n },\n\n getCanvasCenter: function() {\n return new $.Point(this.canvas.width / 2, this.canvas.height / 2);\n },\n\n // private\n _offsetForRotation: function(options) {\n var point = options.point ?\n options.point.times($.pixelDensityRatio) :\n this.getCanvasCenter();\n\n var context = this._getContext(options.useSketch);\n context.save();\n\n context.translate(point.x, point.y);\n context.rotate(Math.PI / 180 * options.degrees);\n context.translate(-point.x, -point.y);\n },\n\n // private\n _restoreRotationChanges: function(useSketch) {\n var context = this._getContext(useSketch);\n context.restore();\n },\n\n // private\n _calculateCanvasSize: function() {\n var pixelDensityRatio = $.pixelDensityRatio;\n var viewportSize = this.viewport.getContainerSize();\n return {\n x: viewportSize.x * pixelDensityRatio,\n y: viewportSize.y * pixelDensityRatio\n };\n },\n\n // private\n _calculateSketchCanvasSize: function() {\n var canvasSize = this._calculateCanvasSize();\n if (this.viewport.getRotation() === 0) {\n return canvasSize;\n }\n // If the viewport is rotated, we need a larger sketch canvas in order\n // to support edge smoothing.\n var sketchCanvasSize = Math.ceil(Math.sqrt(\n canvasSize.x * canvasSize.x +\n canvasSize.y * canvasSize.y));\n return {\n x: sketchCanvasSize,\n y: sketchCanvasSize\n };\n }\n};\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - Viewport\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n\n/**\n * @class Viewport\n * @memberof OpenSeadragon\n * @classdesc Handles coordinate-related functionality (zoom, pan, rotation, etc.)\n * for an {@link OpenSeadragon.Viewer}.\n * @param {Object} options - Options for this Viewport.\n * @param {Object} [options.margins] - See viewportMargins in {@link OpenSeadragon.Options}.\n * @param {Number} [options.springStiffness] - See springStiffness in {@link OpenSeadragon.Options}.\n * @param {Number} [options.animationTime] - See animationTime in {@link OpenSeadragon.Options}.\n * @param {Number} [options.minZoomImageRatio] - See minZoomImageRatio in {@link OpenSeadragon.Options}.\n * @param {Number} [options.maxZoomPixelRatio] - See maxZoomPixelRatio in {@link OpenSeadragon.Options}.\n * @param {Number} [options.visibilityRatio] - See visibilityRatio in {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.wrapHorizontal] - See wrapHorizontal in {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.wrapVertical] - See wrapVertical in {@link OpenSeadragon.Options}.\n * @param {Number} [options.defaultZoomLevel] - See defaultZoomLevel in {@link OpenSeadragon.Options}.\n * @param {Number} [options.minZoomLevel] - See minZoomLevel in {@link OpenSeadragon.Options}.\n * @param {Number} [options.maxZoomLevel] - See maxZoomLevel in {@link OpenSeadragon.Options}.\n * @param {Number} [options.degrees] - See degrees in {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.homeFillsViewer] - See homeFillsViewer in {@link OpenSeadragon.Options}.\n */\n$.Viewport = function( options ) {\n\n //backward compatibility for positional args while prefering more\n //idiomatic javascript options object as the only argument\n var args = arguments;\n if (args.length && args[0] instanceof $.Point) {\n options = {\n containerSize: args[0],\n contentSize: args[1],\n config: args[2]\n };\n }\n\n //options.config and the general config argument are deprecated\n //in favor of the more direct specification of optional settings\n //being passed directly on the options object\n if ( options.config ){\n $.extend( true, options, options.config );\n delete options.config;\n }\n\n this._margins = $.extend({\n left: 0,\n top: 0,\n right: 0,\n bottom: 0\n }, options.margins || {});\n\n delete options.margins;\n\n $.extend( true, this, {\n\n //required settings\n containerSize: null,\n contentSize: null,\n\n //internal state properties\n zoomPoint: null,\n viewer: null,\n\n //configurable options\n springStiffness: $.DEFAULT_SETTINGS.springStiffness,\n animationTime: $.DEFAULT_SETTINGS.animationTime,\n minZoomImageRatio: $.DEFAULT_SETTINGS.minZoomImageRatio,\n maxZoomPixelRatio: $.DEFAULT_SETTINGS.maxZoomPixelRatio,\n visibilityRatio: $.DEFAULT_SETTINGS.visibilityRatio,\n wrapHorizontal: $.DEFAULT_SETTINGS.wrapHorizontal,\n wrapVertical: $.DEFAULT_SETTINGS.wrapVertical,\n defaultZoomLevel: $.DEFAULT_SETTINGS.defaultZoomLevel,\n minZoomLevel: $.DEFAULT_SETTINGS.minZoomLevel,\n maxZoomLevel: $.DEFAULT_SETTINGS.maxZoomLevel,\n degrees: $.DEFAULT_SETTINGS.degrees,\n homeFillsViewer: $.DEFAULT_SETTINGS.homeFillsViewer\n\n }, options );\n\n this._updateContainerInnerSize();\n\n this.centerSpringX = new $.Spring({\n initial: 0,\n springStiffness: this.springStiffness,\n animationTime: this.animationTime\n });\n this.centerSpringY = new $.Spring({\n initial: 0,\n springStiffness: this.springStiffness,\n animationTime: this.animationTime\n });\n this.zoomSpring = new $.Spring({\n exponential: true,\n initial: 1,\n springStiffness: this.springStiffness,\n animationTime: this.animationTime\n });\n\n this._oldCenterX = this.centerSpringX.current.value;\n this._oldCenterY = this.centerSpringY.current.value;\n this._oldZoom = this.zoomSpring.current.value;\n\n this._setContentBounds(new $.Rect(0, 0, 1, 1), 1);\n\n this.goHome(true);\n this.update();\n};\n\n/** @lends OpenSeadragon.Viewport.prototype */\n$.Viewport.prototype = {\n /**\n * Updates the viewport's home bounds and constraints for the given content size.\n * @function\n * @param {OpenSeadragon.Point} contentSize - size of the content in content units\n * @return {OpenSeadragon.Viewport} Chainable.\n * @fires OpenSeadragon.Viewer.event:reset-size\n */\n resetContentSize: function(contentSize) {\n $.console.assert(contentSize, \"[Viewport.resetContentSize] contentSize is required\");\n $.console.assert(contentSize instanceof $.Point, \"[Viewport.resetContentSize] contentSize must be an OpenSeadragon.Point\");\n $.console.assert(contentSize.x > 0, \"[Viewport.resetContentSize] contentSize.x must be greater than 0\");\n $.console.assert(contentSize.y > 0, \"[Viewport.resetContentSize] contentSize.y must be greater than 0\");\n\n this._setContentBounds(new $.Rect(0, 0, 1, contentSize.y / contentSize.x), contentSize.x);\n return this;\n },\n\n // deprecated\n setHomeBounds: function(bounds, contentFactor) {\n $.console.error(\"[Viewport.setHomeBounds] this function is deprecated; The content bounds should not be set manually.\");\n this._setContentBounds(bounds, contentFactor);\n },\n\n // Set the viewport's content bounds\n // @param {OpenSeadragon.Rect} bounds - the new bounds in viewport coordinates\n // without rotation\n // @param {Number} contentFactor - how many content units per viewport unit\n // @fires OpenSeadragon.Viewer.event:reset-size\n // @private\n _setContentBounds: function(bounds, contentFactor) {\n $.console.assert(bounds, \"[Viewport._setContentBounds] bounds is required\");\n $.console.assert(bounds instanceof $.Rect, \"[Viewport._setContentBounds] bounds must be an OpenSeadragon.Rect\");\n $.console.assert(bounds.width > 0, \"[Viewport._setContentBounds] bounds.width must be greater than 0\");\n $.console.assert(bounds.height > 0, \"[Viewport._setContentBounds] bounds.height must be greater than 0\");\n\n this._contentBoundsNoRotate = bounds.clone();\n this._contentSizeNoRotate = this._contentBoundsNoRotate.getSize().times(\n contentFactor);\n\n this._contentBounds = bounds.rotate(this.degrees).getBoundingBox();\n this._contentSize = this._contentBounds.getSize().times(contentFactor);\n this._contentAspectRatio = this._contentSize.x / this._contentSize.y;\n\n if (this.viewer) {\n /**\n * Raised when the viewer's content size or home bounds are reset\n * (see {@link OpenSeadragon.Viewport#resetContentSize}).\n *\n * @event reset-size\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.Point} contentSize\n * @property {OpenSeadragon.Rect} contentBounds - Content bounds.\n * @property {OpenSeadragon.Rect} homeBounds - Content bounds.\n * Deprecated use contentBounds instead.\n * @property {Number} contentFactor\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.viewer.raiseEvent('reset-size', {\n contentSize: this._contentSizeNoRotate.clone(),\n contentFactor: contentFactor,\n homeBounds: this._contentBoundsNoRotate.clone(),\n contentBounds: this._contentBounds.clone()\n });\n }\n },\n\n /**\n * Returns the home zoom in \"viewport zoom\" value.\n * @function\n * @returns {Number} The home zoom in \"viewport zoom\".\n */\n getHomeZoom: function() {\n if (this.defaultZoomLevel) {\n return this.defaultZoomLevel;\n }\n\n var aspectFactor = this._contentAspectRatio / this.getAspectRatio();\n var output;\n if (this.homeFillsViewer) { // fill the viewer and clip the image\n output = aspectFactor >= 1 ? aspectFactor : 1;\n } else {\n output = aspectFactor >= 1 ? 1 : aspectFactor;\n }\n\n return output / this._contentBounds.width;\n },\n\n /**\n * Returns the home bounds in viewport coordinates.\n * @function\n * @returns {OpenSeadragon.Rect} The home bounds in vewport coordinates.\n */\n getHomeBounds: function() {\n return this.getHomeBoundsNoRotate().rotate(-this.getRotation());\n },\n\n /**\n * Returns the home bounds in viewport coordinates.\n * This method ignores the viewport rotation. Use\n * {@link OpenSeadragon.Viewport#getHomeBounds} to take it into account.\n * @function\n * @returns {OpenSeadragon.Rect} The home bounds in vewport coordinates.\n */\n getHomeBoundsNoRotate: function() {\n var center = this._contentBounds.getCenter();\n var width = 1.0 / this.getHomeZoom();\n var height = width / this.getAspectRatio();\n\n return new $.Rect(\n center.x - (width / 2.0),\n center.y - (height / 2.0),\n width,\n height\n );\n },\n\n /**\n * @function\n * @param {Boolean} immediately\n * @fires OpenSeadragon.Viewer.event:home\n */\n goHome: function(immediately) {\n if (this.viewer) {\n /**\n * Raised when the \"home\" operation occurs (see {@link OpenSeadragon.Viewport#goHome}).\n *\n * @event home\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {Boolean} immediately\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.viewer.raiseEvent('home', {\n immediately: immediately\n });\n }\n return this.fitBounds(this.getHomeBounds(), immediately);\n },\n\n /**\n * @function\n */\n getMinZoom: function() {\n var homeZoom = this.getHomeZoom(),\n zoom = this.minZoomLevel ?\n this.minZoomLevel :\n this.minZoomImageRatio * homeZoom;\n\n return zoom;\n },\n\n /**\n * @function\n */\n getMaxZoom: function() {\n var zoom = this.maxZoomLevel;\n if (!zoom) {\n zoom = this._contentSize.x * this.maxZoomPixelRatio / this._containerInnerSize.x;\n zoom /= this._contentBounds.width;\n }\n\n return Math.max( zoom, this.getHomeZoom() );\n },\n\n /**\n * @function\n */\n getAspectRatio: function() {\n return this._containerInnerSize.x / this._containerInnerSize.y;\n },\n\n /**\n * @function\n * @returns {OpenSeadragon.Point} The size of the container, in screen coordinates.\n */\n getContainerSize: function() {\n return new $.Point(\n this.containerSize.x,\n this.containerSize.y\n );\n },\n\n /**\n * The margins push the \"home\" region in from the sides by the specified amounts.\n * @function\n * @returns {Object} Properties (Numbers, in screen coordinates): left, top, right, bottom.\n */\n getMargins: function() {\n return $.extend({}, this._margins); // Make a copy so we are not returning our original\n },\n\n /**\n * The margins push the \"home\" region in from the sides by the specified amounts.\n * @function\n * @param {Object} margins - Properties (Numbers, in screen coordinates): left, top, right, bottom.\n */\n setMargins: function(margins) {\n $.console.assert($.type(margins) === 'object', '[Viewport.setMargins] margins must be an object');\n\n this._margins = $.extend({\n left: 0,\n top: 0,\n right: 0,\n bottom: 0\n }, margins);\n\n this._updateContainerInnerSize();\n if (this.viewer) {\n this.viewer.forceRedraw();\n }\n },\n\n /**\n * Returns the bounds of the visible area in viewport coordinates.\n * @function\n * @param {Boolean} current - Pass true for the current location; defaults to false (target location).\n * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, in viewport coordinates.\n */\n getBounds: function(current) {\n return this.getBoundsNoRotate(current).rotate(-this.getRotation());\n },\n\n /**\n * Returns the bounds of the visible area in viewport coordinates.\n * This method ignores the viewport rotation. Use\n * {@link OpenSeadragon.Viewport#getBounds} to take it into account.\n * @function\n * @param {Boolean} current - Pass true for the current location; defaults to false (target location).\n * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, in viewport coordinates.\n */\n getBoundsNoRotate: function(current) {\n var center = this.getCenter(current);\n var width = 1.0 / this.getZoom(current);\n var height = width / this.getAspectRatio();\n\n return new $.Rect(\n center.x - (width / 2.0),\n center.y - (height / 2.0),\n width,\n height\n );\n },\n\n /**\n * @function\n * @param {Boolean} current - Pass true for the current location; defaults to false (target location).\n * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to,\n * including the space taken by margins, in viewport coordinates.\n */\n getBoundsWithMargins: function(current) {\n return this.getBoundsNoRotateWithMargins(current).rotate(\n -this.getRotation(), this.getCenter(current));\n },\n\n /**\n * @function\n * @param {Boolean} current - Pass true for the current location; defaults to false (target location).\n * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to,\n * including the space taken by margins, in viewport coordinates.\n */\n getBoundsNoRotateWithMargins: function(current) {\n var bounds = this.getBoundsNoRotate(current);\n var factor = this._containerInnerSize.x * this.getZoom(current);\n bounds.x -= this._margins.left / factor;\n bounds.y -= this._margins.top / factor;\n bounds.width += (this._margins.left + this._margins.right) / factor;\n bounds.height += (this._margins.top + this._margins.bottom) / factor;\n return bounds;\n },\n\n /**\n * @function\n * @param {Boolean} current - Pass true for the current location; defaults to false (target location).\n */\n getCenter: function( current ) {\n var centerCurrent = new $.Point(\n this.centerSpringX.current.value,\n this.centerSpringY.current.value\n ),\n centerTarget = new $.Point(\n this.centerSpringX.target.value,\n this.centerSpringY.target.value\n ),\n oldZoomPixel,\n zoom,\n width,\n height,\n bounds,\n newZoomPixel,\n deltaZoomPixels,\n deltaZoomPoints;\n\n if ( current ) {\n return centerCurrent;\n } else if ( !this.zoomPoint ) {\n return centerTarget;\n }\n\n oldZoomPixel = this.pixelFromPoint(this.zoomPoint, true);\n\n zoom = this.getZoom();\n width = 1.0 / zoom;\n height = width / this.getAspectRatio();\n bounds = new $.Rect(\n centerCurrent.x - width / 2.0,\n centerCurrent.y - height / 2.0,\n width,\n height\n );\n\n newZoomPixel = this._pixelFromPoint(this.zoomPoint, bounds);\n deltaZoomPixels = newZoomPixel.minus( oldZoomPixel );\n deltaZoomPoints = deltaZoomPixels.divide( this._containerInnerSize.x * zoom );\n\n return centerTarget.plus( deltaZoomPoints );\n },\n\n /**\n * @function\n * @param {Boolean} current - Pass true for the current location; defaults to false (target location).\n */\n getZoom: function( current ) {\n if ( current ) {\n return this.zoomSpring.current.value;\n } else {\n return this.zoomSpring.target.value;\n }\n },\n\n // private\n _applyZoomConstraints: function(zoom) {\n return Math.max(\n Math.min(zoom, this.getMaxZoom()),\n this.getMinZoom());\n },\n\n /**\n * @function\n * @private\n * @param {OpenSeadragon.Rect} bounds\n * @return {OpenSeadragon.Rect} constrained bounds.\n */\n _applyBoundaryConstraints: function(bounds) {\n var newBounds = new $.Rect(\n bounds.x,\n bounds.y,\n bounds.width,\n bounds.height);\n\n if (this.wrapHorizontal) {\n //do nothing\n } else {\n var horizontalThreshold = this.visibilityRatio * newBounds.width;\n var boundsRight = newBounds.x + newBounds.width;\n var contentRight = this._contentBoundsNoRotate.x + this._contentBoundsNoRotate.width;\n var leftDx = this._contentBoundsNoRotate.x - boundsRight + horizontalThreshold;\n var rightDx = contentRight - newBounds.x - horizontalThreshold;\n\n if (horizontalThreshold > this._contentBoundsNoRotate.width) {\n newBounds.x += (leftDx + rightDx) / 2;\n } else if (rightDx < 0) {\n newBounds.x += rightDx;\n } else if (leftDx > 0) {\n newBounds.x += leftDx;\n }\n }\n\n if (this.wrapVertical) {\n //do nothing\n } else {\n var verticalThreshold = this.visibilityRatio * newBounds.height;\n var boundsBottom = newBounds.y + newBounds.height;\n var contentBottom = this._contentBoundsNoRotate.y + this._contentBoundsNoRotate.height;\n var topDy = this._contentBoundsNoRotate.y - boundsBottom + verticalThreshold;\n var bottomDy = contentBottom - newBounds.y - verticalThreshold;\n\n if (verticalThreshold > this._contentBoundsNoRotate.height) {\n newBounds.y += (topDy + bottomDy) / 2;\n } else if (bottomDy < 0) {\n newBounds.y += bottomDy;\n } else if (topDy > 0) {\n newBounds.y += topDy;\n }\n }\n\n return newBounds;\n },\n\n /**\n * @function\n * @private\n * @param {Boolean} [immediately=false] - whether the function that triggered this event was\n * called with the \"immediately\" flag\n */\n _raiseConstraintsEvent: function(immediately) {\n if (this.viewer) {\n /**\n * Raised when the viewport constraints are applied (see {@link OpenSeadragon.Viewport#applyConstraints}).\n *\n * @event constrain\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {Boolean} immediately - whether the function that triggered this event was\n * called with the \"immediately\" flag\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.viewer.raiseEvent( 'constrain', {\n immediately: immediately\n });\n }\n },\n\n /**\n * Enforces the minZoom, maxZoom and visibilityRatio constraints by\n * zooming and panning to the closest acceptable zoom and location.\n * @function\n * @param {Boolean} [immediately=false]\n * @return {OpenSeadragon.Viewport} Chainable.\n * @fires OpenSeadragon.Viewer.event:constrain\n */\n applyConstraints: function(immediately) {\n var actualZoom = this.getZoom();\n var constrainedZoom = this._applyZoomConstraints(actualZoom);\n\n if (actualZoom !== constrainedZoom) {\n this.zoomTo(constrainedZoom, this.zoomPoint, immediately);\n }\n\n var bounds = this.getBoundsNoRotate();\n var constrainedBounds = this._applyBoundaryConstraints(bounds);\n this._raiseConstraintsEvent(immediately);\n\n if (bounds.x !== constrainedBounds.x ||\n bounds.y !== constrainedBounds.y ||\n immediately) {\n this.fitBounds(\n constrainedBounds.rotate(-this.getRotation()),\n immediately);\n }\n return this;\n },\n\n /**\n * Equivalent to {@link OpenSeadragon.Viewport#applyConstraints}\n * @function\n * @param {Boolean} [immediately=false]\n * @return {OpenSeadragon.Viewport} Chainable.\n * @fires OpenSeadragon.Viewer.event:constrain\n */\n ensureVisible: function(immediately) {\n return this.applyConstraints(immediately);\n },\n\n /**\n * @function\n * @private\n * @param {OpenSeadragon.Rect} bounds\n * @param {Object} options (immediately=false, constraints=false)\n * @return {OpenSeadragon.Viewport} Chainable.\n */\n _fitBounds: function(bounds, options) {\n options = options || {};\n var immediately = options.immediately || false;\n var constraints = options.constraints || false;\n\n var aspect = this.getAspectRatio();\n var center = bounds.getCenter();\n\n // Compute width and height of bounding box.\n var newBounds = new $.Rect(\n bounds.x,\n bounds.y,\n bounds.width,\n bounds.height,\n bounds.degrees + this.getRotation())\n .getBoundingBox();\n\n if (newBounds.getAspectRatio() >= aspect) {\n newBounds.height = newBounds.width / aspect;\n } else {\n newBounds.width = newBounds.height * aspect;\n }\n\n // Compute x and y from width, height and center position\n newBounds.x = center.x - newBounds.width / 2;\n newBounds.y = center.y - newBounds.height / 2;\n var newZoom = 1.0 / newBounds.width;\n\n if (constraints) {\n var newBoundsAspectRatio = newBounds.getAspectRatio();\n var newConstrainedZoom = this._applyZoomConstraints(newZoom);\n\n if (newZoom !== newConstrainedZoom) {\n newZoom = newConstrainedZoom;\n newBounds.width = 1.0 / newZoom;\n newBounds.x = center.x - newBounds.width / 2;\n newBounds.height = newBounds.width / newBoundsAspectRatio;\n newBounds.y = center.y - newBounds.height / 2;\n }\n\n newBounds = this._applyBoundaryConstraints(newBounds);\n center = newBounds.getCenter();\n this._raiseConstraintsEvent(immediately);\n }\n\n if (immediately) {\n this.panTo(center, true);\n return this.zoomTo(newZoom, null, true);\n }\n\n this.panTo(this.getCenter(true), true);\n this.zoomTo(this.getZoom(true), null, true);\n\n var oldBounds = this.getBounds();\n var oldZoom = this.getZoom();\n\n if (oldZoom === 0 || Math.abs(newZoom / oldZoom - 1) < 0.00000001) {\n this.zoomTo(newZoom, true);\n return this.panTo(center, immediately);\n }\n\n newBounds = newBounds.rotate(-this.getRotation());\n var referencePoint = newBounds.getTopLeft().times(newZoom)\n .minus(oldBounds.getTopLeft().times(oldZoom))\n .divide(newZoom - oldZoom);\n\n return this.zoomTo(newZoom, referencePoint, immediately);\n },\n\n /**\n * Makes the viewport zoom and pan so that the specified bounds take\n * as much space as possible in the viewport.\n * Note: this method ignores the constraints (minZoom, maxZoom and\n * visibilityRatio).\n * Use {@link OpenSeadragon.Viewport#fitBoundsWithConstraints} to enforce\n * them.\n * @function\n * @param {OpenSeadragon.Rect} bounds\n * @param {Boolean} [immediately=false]\n * @return {OpenSeadragon.Viewport} Chainable.\n */\n fitBounds: function(bounds, immediately) {\n return this._fitBounds(bounds, {\n immediately: immediately,\n constraints: false\n });\n },\n\n /**\n * Makes the viewport zoom and pan so that the specified bounds take\n * as much space as possible in the viewport while enforcing the constraints\n * (minZoom, maxZoom and visibilityRatio).\n * Note: because this method enforces the constraints, part of the\n * provided bounds may end up outside of the viewport.\n * Use {@link OpenSeadragon.Viewport#fitBounds} to ignore them.\n * @function\n * @param {OpenSeadragon.Rect} bounds\n * @param {Boolean} [immediately=false]\n * @return {OpenSeadragon.Viewport} Chainable.\n */\n fitBoundsWithConstraints: function(bounds, immediately) {\n return this._fitBounds(bounds, {\n immediately: immediately,\n constraints: true\n });\n },\n\n /**\n * Zooms so the image just fills the viewer vertically.\n * @param {Boolean} immediately\n * @return {OpenSeadragon.Viewport} Chainable.\n */\n fitVertically: function(immediately) {\n var box = new $.Rect(\n this._contentBounds.x + (this._contentBounds.width / 2),\n this._contentBounds.y,\n 0,\n this._contentBounds.height);\n return this.fitBounds(box, immediately);\n },\n\n /**\n * Zooms so the image just fills the viewer horizontally.\n * @param {Boolean} immediately\n * @return {OpenSeadragon.Viewport} Chainable.\n */\n fitHorizontally: function(immediately) {\n var box = new $.Rect(\n this._contentBounds.x,\n this._contentBounds.y + (this._contentBounds.height / 2),\n this._contentBounds.width,\n 0);\n return this.fitBounds(box, immediately);\n },\n\n\n /**\n * Returns bounds taking constraints into account\n * Added to improve constrained panning\n * @param {Boolean} current - Pass true for the current location; defaults to false (target location).\n * @return {OpenSeadragon.Viewport} Chainable.\n */\n getConstrainedBounds: function(current) {\n var bounds,\n constrainedBounds;\n\n bounds = this.getBounds(current);\n\n constrainedBounds = this._applyBoundaryConstraints(bounds);\n\n return constrainedBounds;\n },\n\n /**\n * @function\n * @param {OpenSeadragon.Point} delta\n * @param {Boolean} immediately\n * @return {OpenSeadragon.Viewport} Chainable.\n * @fires OpenSeadragon.Viewer.event:pan\n */\n panBy: function( delta, immediately ) {\n var center = new $.Point(\n this.centerSpringX.target.value,\n this.centerSpringY.target.value\n );\n return this.panTo( center.plus( delta ), immediately );\n },\n\n /**\n * @function\n * @param {OpenSeadragon.Point} center\n * @param {Boolean} immediately\n * @return {OpenSeadragon.Viewport} Chainable.\n * @fires OpenSeadragon.Viewer.event:pan\n */\n panTo: function( center, immediately ) {\n if ( immediately ) {\n this.centerSpringX.resetTo( center.x );\n this.centerSpringY.resetTo( center.y );\n } else {\n this.centerSpringX.springTo( center.x );\n this.centerSpringY.springTo( center.y );\n }\n\n if( this.viewer ){\n /**\n * Raised when the viewport is panned (see {@link OpenSeadragon.Viewport#panBy} and {@link OpenSeadragon.Viewport#panTo}).\n *\n * @event pan\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.Point} center\n * @property {Boolean} immediately\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.viewer.raiseEvent( 'pan', {\n center: center,\n immediately: immediately\n });\n }\n\n return this;\n },\n\n /**\n * @function\n * @return {OpenSeadragon.Viewport} Chainable.\n * @fires OpenSeadragon.Viewer.event:zoom\n */\n zoomBy: function(factor, refPoint, immediately) {\n return this.zoomTo(\n this.zoomSpring.target.value * factor, refPoint, immediately);\n },\n\n /**\n * Zooms to the specified zoom level\n * @function\n * @param {Number} zoom The zoom level to zoom to.\n * @param {OpenSeadragon.Point} [refPoint] The point which will stay at\n * the same screen location. Defaults to the viewport center.\n * @param {Boolean} [immediately=false]\n * @return {OpenSeadragon.Viewport} Chainable.\n * @fires OpenSeadragon.Viewer.event:zoom\n */\n zoomTo: function(zoom, refPoint, immediately) {\n var _this = this;\n\n this.zoomPoint = refPoint instanceof $.Point &&\n !isNaN(refPoint.x) &&\n !isNaN(refPoint.y) ?\n refPoint :\n null;\n\n if (immediately) {\n this._adjustCenterSpringsForZoomPoint(function() {\n _this.zoomSpring.resetTo(zoom);\n });\n } else {\n this.zoomSpring.springTo(zoom);\n }\n\n if (this.viewer) {\n /**\n * Raised when the viewport zoom level changes (see {@link OpenSeadragon.Viewport#zoomBy} and {@link OpenSeadragon.Viewport#zoomTo}).\n *\n * @event zoom\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {Number} zoom\n * @property {OpenSeadragon.Point} refPoint\n * @property {Boolean} immediately\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.viewer.raiseEvent('zoom', {\n zoom: zoom,\n refPoint: refPoint,\n immediately: immediately\n });\n }\n\n return this;\n },\n\n /**\n * Rotates this viewport to the angle specified.\n * @function\n * @return {OpenSeadragon.Viewport} Chainable.\n */\n setRotation: function(degrees) {\n if (!this.viewer || !this.viewer.drawer.canRotate()) {\n return this;\n }\n\n this.degrees = $.positiveModulo(degrees, 360);\n this._setContentBounds(\n this.viewer.world.getHomeBounds(),\n this.viewer.world.getContentFactor());\n this.viewer.forceRedraw();\n\n /**\n * Raised when rotation has been changed.\n *\n * @event rotate\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Number} degrees - The number of degrees the rotation was set to.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.viewer.raiseEvent('rotate', {\"degrees\": degrees});\n return this;\n },\n\n /**\n * Gets the current rotation in degrees.\n * @function\n * @return {Number} The current rotation in degrees.\n */\n getRotation: function() {\n return this.degrees;\n },\n\n /**\n * @function\n * @return {OpenSeadragon.Viewport} Chainable.\n * @fires OpenSeadragon.Viewer.event:resize\n */\n resize: function( newContainerSize, maintain ) {\n var oldBounds = this.getBoundsNoRotate(),\n newBounds = oldBounds,\n widthDeltaFactor;\n\n this.containerSize.x = newContainerSize.x;\n this.containerSize.y = newContainerSize.y;\n\n this._updateContainerInnerSize();\n\n if ( maintain ) {\n // TODO: widthDeltaFactor will always be 1; probably not what's intended\n widthDeltaFactor = newContainerSize.x / this.containerSize.x;\n newBounds.width = oldBounds.width * widthDeltaFactor;\n newBounds.height = newBounds.width / this.getAspectRatio();\n }\n\n if( this.viewer ){\n /**\n * Raised when the viewer is resized (see {@link OpenSeadragon.Viewport#resize}).\n *\n * @event resize\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.Point} newContainerSize\n * @property {Boolean} maintain\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.viewer.raiseEvent( 'resize', {\n newContainerSize: newContainerSize,\n maintain: maintain\n });\n }\n\n return this.fitBounds( newBounds, true );\n },\n\n // private\n _updateContainerInnerSize: function() {\n this._containerInnerSize = new $.Point(\n Math.max(1, this.containerSize.x - (this._margins.left + this._margins.right)),\n Math.max(1, this.containerSize.y - (this._margins.top + this._margins.bottom))\n );\n },\n\n /**\n * Update the zoom and center (X and Y) springs.\n * @function\n * @returns {Boolean} True if any change has been made, false otherwise.\n */\n update: function() {\n var _this = this;\n this._adjustCenterSpringsForZoomPoint(function() {\n _this.zoomSpring.update();\n });\n\n this.centerSpringX.update();\n this.centerSpringY.update();\n\n var changed = this.centerSpringX.current.value !== this._oldCenterX ||\n this.centerSpringY.current.value !== this._oldCenterY ||\n this.zoomSpring.current.value !== this._oldZoom;\n\n this._oldCenterX = this.centerSpringX.current.value;\n this._oldCenterY = this.centerSpringY.current.value;\n this._oldZoom = this.zoomSpring.current.value;\n\n return changed;\n },\n\n _adjustCenterSpringsForZoomPoint: function(zoomSpringHandler) {\n if (this.zoomPoint) {\n var oldZoomPixel = this.pixelFromPoint(this.zoomPoint, true);\n zoomSpringHandler();\n var newZoomPixel = this.pixelFromPoint(this.zoomPoint, true);\n\n var deltaZoomPixels = newZoomPixel.minus(oldZoomPixel);\n var deltaZoomPoints = this.deltaPointsFromPixels(\n deltaZoomPixels, true);\n\n this.centerSpringX.shiftBy(deltaZoomPoints.x);\n this.centerSpringY.shiftBy(deltaZoomPoints.y);\n\n if (this.zoomSpring.isAtTargetValue()) {\n this.zoomPoint = null;\n }\n } else {\n zoomSpringHandler();\n }\n },\n\n /**\n * Convert a delta (translation vector) from viewport coordinates to pixels\n * coordinates. This method does not take rotation into account.\n * Consider using deltaPixelsFromPoints if you need to account for rotation.\n * @param {OpenSeadragon.Point} deltaPoints - The translation vector to convert.\n * @param {Boolean} [current=false] - Pass true for the current location;\n * defaults to false (target location).\n * @returns {OpenSeadragon.Point}\n */\n deltaPixelsFromPointsNoRotate: function(deltaPoints, current) {\n return deltaPoints.times(\n this._containerInnerSize.x * this.getZoom(current)\n );\n },\n\n /**\n * Convert a delta (translation vector) from viewport coordinates to pixels\n * coordinates.\n * @param {OpenSeadragon.Point} deltaPoints - The translation vector to convert.\n * @param {Boolean} [current=false] - Pass true for the current location;\n * defaults to false (target location).\n * @returns {OpenSeadragon.Point}\n */\n deltaPixelsFromPoints: function(deltaPoints, current) {\n return this.deltaPixelsFromPointsNoRotate(\n deltaPoints.rotate(this.getRotation()),\n current);\n },\n\n /**\n * Convert a delta (translation vector) from pixels coordinates to viewport\n * coordinates. This method does not take rotation into account.\n * Consider using deltaPointsFromPixels if you need to account for rotation.\n * @param {OpenSeadragon.Point} deltaPixels - The translation vector to convert.\n * @param {Boolean} [current=false] - Pass true for the current location;\n * defaults to false (target location).\n * @returns {OpenSeadragon.Point}\n */\n deltaPointsFromPixelsNoRotate: function(deltaPixels, current) {\n return deltaPixels.divide(\n this._containerInnerSize.x * this.getZoom(current)\n );\n },\n\n /**\n * Convert a delta (translation vector) from pixels coordinates to viewport\n * coordinates.\n * @param {OpenSeadragon.Point} deltaPixels - The translation vector to convert.\n * @param {Boolean} [current=false] - Pass true for the current location;\n * defaults to false (target location).\n * @returns {OpenSeadragon.Point}\n */\n deltaPointsFromPixels: function(deltaPixels, current) {\n return this.deltaPointsFromPixelsNoRotate(deltaPixels, current)\n .rotate(-this.getRotation());\n },\n\n /**\n * Convert viewport coordinates to pixels coordinates.\n * This method does not take rotation into account.\n * Consider using pixelFromPoint if you need to account for rotation.\n * @param {OpenSeadragon.Point} point the viewport coordinates\n * @param {Boolean} [current=false] - Pass true for the current location;\n * defaults to false (target location).\n * @returns {OpenSeadragon.Point}\n */\n pixelFromPointNoRotate: function(point, current) {\n return this._pixelFromPointNoRotate(\n point, this.getBoundsNoRotate(current));\n },\n\n /**\n * Convert viewport coordinates to pixel coordinates.\n * @param {OpenSeadragon.Point} point the viewport coordinates\n * @param {Boolean} [current=false] - Pass true for the current location;\n * defaults to false (target location).\n * @returns {OpenSeadragon.Point}\n */\n pixelFromPoint: function(point, current) {\n return this._pixelFromPoint(point, this.getBoundsNoRotate(current));\n },\n\n // private\n _pixelFromPointNoRotate: function(point, bounds) {\n return point.minus(\n bounds.getTopLeft()\n ).times(\n this._containerInnerSize.x / bounds.width\n ).plus(\n new $.Point(this._margins.left, this._margins.top)\n );\n },\n\n // private\n _pixelFromPoint: function(point, bounds) {\n return this._pixelFromPointNoRotate(\n point.rotate(this.getRotation(), this.getCenter(true)),\n bounds);\n },\n\n /**\n * Convert pixel coordinates to viewport coordinates.\n * This method does not take rotation into account.\n * Consider using pointFromPixel if you need to account for rotation.\n * @param {OpenSeadragon.Point} pixel Pixel coordinates\n * @param {Boolean} [current=false] - Pass true for the current location;\n * defaults to false (target location).\n * @returns {OpenSeadragon.Point}\n */\n pointFromPixelNoRotate: function(pixel, current) {\n var bounds = this.getBoundsNoRotate(current);\n return pixel.minus(\n new $.Point(this._margins.left, this._margins.top)\n ).divide(\n this._containerInnerSize.x / bounds.width\n ).plus(\n bounds.getTopLeft()\n );\n },\n\n /**\n * Convert pixel coordinates to viewport coordinates.\n * @param {OpenSeadragon.Point} pixel Pixel coordinates\n * @param {Boolean} [current=false] - Pass true for the current location;\n * defaults to false (target location).\n * @returns {OpenSeadragon.Point}\n */\n pointFromPixel: function(pixel, current) {\n return this.pointFromPixelNoRotate(pixel, current).rotate(\n -this.getRotation(),\n this.getCenter(true)\n );\n },\n\n // private\n _viewportToImageDelta: function( viewerX, viewerY ) {\n var scale = this._contentBoundsNoRotate.width;\n return new $.Point(\n viewerX * this._contentSizeNoRotate.x / scale,\n viewerY * this._contentSizeNoRotate.x / scale);\n },\n\n /**\n * Translates from OpenSeadragon viewer coordinate system to image coordinate system.\n * This method can be called either by passing X,Y coordinates or an\n * OpenSeadragon.Point\n * Note: not accurate with multi-image; use TiledImage.viewportToImageCoordinates instead.\n * @function\n * @param {(OpenSeadragon.Point|Number)} viewerX either a point or the X\n * coordinate in viewport coordinate system.\n * @param {Number} [viewerY] Y coordinate in viewport coordinate system.\n * @return {OpenSeadragon.Point} a point representing the coordinates in the image.\n */\n viewportToImageCoordinates: function(viewerX, viewerY) {\n if (viewerX instanceof $.Point) {\n //they passed a point instead of individual components\n return this.viewportToImageCoordinates(viewerX.x, viewerX.y);\n }\n\n if (this.viewer) {\n var count = this.viewer.world.getItemCount();\n if (count > 1) {\n $.console.error('[Viewport.viewportToImageCoordinates] is not accurate ' +\n 'with multi-image; use TiledImage.viewportToImageCoordinates instead.');\n } else if (count === 1) {\n // It is better to use TiledImage.viewportToImageCoordinates\n // because this._contentBoundsNoRotate can not be relied on\n // with clipping.\n var item = this.viewer.world.getItemAt(0);\n return item.viewportToImageCoordinates(viewerX, viewerY, true);\n }\n }\n\n return this._viewportToImageDelta(\n viewerX - this._contentBoundsNoRotate.x,\n viewerY - this._contentBoundsNoRotate.y);\n },\n\n // private\n _imageToViewportDelta: function( imageX, imageY ) {\n var scale = this._contentBoundsNoRotate.width;\n return new $.Point(\n imageX / this._contentSizeNoRotate.x * scale,\n imageY / this._contentSizeNoRotate.x * scale);\n },\n\n /**\n * Translates from image coordinate system to OpenSeadragon viewer coordinate system\n * This method can be called either by passing X,Y coordinates or an\n * OpenSeadragon.Point\n * Note: not accurate with multi-image; use TiledImage.imageToViewportCoordinates instead.\n * @function\n * @param {(OpenSeadragon.Point | Number)} imageX the point or the\n * X coordinate in image coordinate system.\n * @param {Number} [imageY] Y coordinate in image coordinate system.\n * @return {OpenSeadragon.Point} a point representing the coordinates in the viewport.\n */\n imageToViewportCoordinates: function(imageX, imageY) {\n if (imageX instanceof $.Point) {\n //they passed a point instead of individual components\n return this.imageToViewportCoordinates(imageX.x, imageX.y);\n }\n\n if (this.viewer) {\n var count = this.viewer.world.getItemCount();\n if (count > 1) {\n $.console.error('[Viewport.imageToViewportCoordinates] is not accurate ' +\n 'with multi-image; use TiledImage.imageToViewportCoordinates instead.');\n } else if (count === 1) {\n // It is better to use TiledImage.viewportToImageCoordinates\n // because this._contentBoundsNoRotate can not be relied on\n // with clipping.\n var item = this.viewer.world.getItemAt(0);\n return item.imageToViewportCoordinates(imageX, imageY, true);\n }\n }\n\n var point = this._imageToViewportDelta(imageX, imageY);\n point.x += this._contentBoundsNoRotate.x;\n point.y += this._contentBoundsNoRotate.y;\n return point;\n },\n\n /**\n * Translates from a rectangle which describes a portion of the image in\n * pixel coordinates to OpenSeadragon viewport rectangle coordinates.\n * This method can be called either by passing X,Y,width,height or an\n * OpenSeadragon.Rect\n * Note: not accurate with multi-image; use TiledImage.imageToViewportRectangle instead.\n * @function\n * @param {(OpenSeadragon.Rect | Number)} imageX the rectangle or the X\n * coordinate of the top left corner of the rectangle in image coordinate system.\n * @param {Number} [imageY] the Y coordinate of the top left corner of the rectangle\n * in image coordinate system.\n * @param {Number} [pixelWidth] the width in pixel of the rectangle.\n * @param {Number} [pixelHeight] the height in pixel of the rectangle.\n * @returns {OpenSeadragon.Rect} This image's bounds in viewport coordinates\n */\n imageToViewportRectangle: function(imageX, imageY, pixelWidth, pixelHeight) {\n var rect = imageX;\n if (!(rect instanceof $.Rect)) {\n //they passed individual components instead of a rectangle\n rect = new $.Rect(imageX, imageY, pixelWidth, pixelHeight);\n }\n\n if (this.viewer) {\n var count = this.viewer.world.getItemCount();\n if (count > 1) {\n $.console.error('[Viewport.imageToViewportRectangle] is not accurate ' +\n 'with multi-image; use TiledImage.imageToViewportRectangle instead.');\n } else if (count === 1) {\n // It is better to use TiledImage.imageToViewportRectangle\n // because this._contentBoundsNoRotate can not be relied on\n // with clipping.\n var item = this.viewer.world.getItemAt(0);\n return item.imageToViewportRectangle(\n imageX, imageY, pixelWidth, pixelHeight, true);\n }\n }\n\n var coordA = this.imageToViewportCoordinates(rect.x, rect.y);\n var coordB = this._imageToViewportDelta(rect.width, rect.height);\n return new $.Rect(\n coordA.x,\n coordA.y,\n coordB.x,\n coordB.y,\n rect.degrees\n );\n },\n\n /**\n * Translates from a rectangle which describes a portion of\n * the viewport in point coordinates to image rectangle coordinates.\n * This method can be called either by passing X,Y,width,height or an\n * OpenSeadragon.Rect\n * Note: not accurate with multi-image; use TiledImage.viewportToImageRectangle instead.\n * @function\n * @param {(OpenSeadragon.Rect | Number)} viewerX either a rectangle or\n * the X coordinate of the top left corner of the rectangle in viewport\n * coordinate system.\n * @param {Number} [viewerY] the Y coordinate of the top left corner of the rectangle\n * in viewport coordinate system.\n * @param {Number} [pointWidth] the width of the rectangle in viewport coordinate system.\n * @param {Number} [pointHeight] the height of the rectangle in viewport coordinate system.\n */\n viewportToImageRectangle: function(viewerX, viewerY, pointWidth, pointHeight) {\n var rect = viewerX;\n if (!(rect instanceof $.Rect)) {\n //they passed individual components instead of a rectangle\n rect = new $.Rect(viewerX, viewerY, pointWidth, pointHeight);\n }\n\n if (this.viewer) {\n var count = this.viewer.world.getItemCount();\n if (count > 1) {\n $.console.error('[Viewport.viewportToImageRectangle] is not accurate ' +\n 'with multi-image; use TiledImage.viewportToImageRectangle instead.');\n } else if (count === 1) {\n // It is better to use TiledImage.viewportToImageCoordinates\n // because this._contentBoundsNoRotate can not be relied on\n // with clipping.\n var item = this.viewer.world.getItemAt(0);\n return item.viewportToImageRectangle(\n viewerX, viewerY, pointWidth, pointHeight, true);\n }\n }\n\n var coordA = this.viewportToImageCoordinates(rect.x, rect.y);\n var coordB = this._viewportToImageDelta(rect.width, rect.height);\n return new $.Rect(\n coordA.x,\n coordA.y,\n coordB.x,\n coordB.y,\n rect.degrees\n );\n },\n\n /**\n * Convert pixel coordinates relative to the viewer element to image\n * coordinates.\n * Note: not accurate with multi-image.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n viewerElementToImageCoordinates: function( pixel ) {\n var point = this.pointFromPixel( pixel, true );\n return this.viewportToImageCoordinates( point );\n },\n\n /**\n * Convert pixel coordinates relative to the image to\n * viewer element coordinates.\n * Note: not accurate with multi-image.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n imageToViewerElementCoordinates: function( pixel ) {\n var point = this.imageToViewportCoordinates( pixel );\n return this.pixelFromPoint( point, true );\n },\n\n /**\n * Convert pixel coordinates relative to the window to image coordinates.\n * Note: not accurate with multi-image.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n windowToImageCoordinates: function(pixel) {\n $.console.assert(this.viewer,\n \"[Viewport.windowToImageCoordinates] the viewport must have a viewer.\");\n var viewerCoordinates = pixel.minus(\n $.getElementPosition(this.viewer.element));\n return this.viewerElementToImageCoordinates(viewerCoordinates);\n },\n\n /**\n * Convert image coordinates to pixel coordinates relative to the window.\n * Note: not accurate with multi-image.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n imageToWindowCoordinates: function(pixel) {\n $.console.assert(this.viewer,\n \"[Viewport.imageToWindowCoordinates] the viewport must have a viewer.\");\n var viewerCoordinates = this.imageToViewerElementCoordinates(pixel);\n return viewerCoordinates.plus(\n $.getElementPosition(this.viewer.element));\n },\n\n /**\n * Convert pixel coordinates relative to the viewer element to viewport\n * coordinates.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n viewerElementToViewportCoordinates: function( pixel ) {\n return this.pointFromPixel( pixel, true );\n },\n\n /**\n * Convert viewport coordinates to pixel coordinates relative to the\n * viewer element.\n * @param {OpenSeadragon.Point} point\n * @returns {OpenSeadragon.Point}\n */\n viewportToViewerElementCoordinates: function( point ) {\n return this.pixelFromPoint( point, true );\n },\n\n /**\n * Convert a rectangle in pixel coordinates relative to the viewer element\n * to viewport coordinates.\n * @param {OpenSeadragon.Rect} rectangle the rectangle to convert\n * @returns {OpenSeadragon.Rect} the converted rectangle\n */\n viewerElementToViewportRectangle: function(rectangle) {\n return $.Rect.fromSummits(\n this.pointFromPixel(rectangle.getTopLeft(), true),\n this.pointFromPixel(rectangle.getTopRight(), true),\n this.pointFromPixel(rectangle.getBottomLeft(), true)\n );\n },\n\n /**\n * Convert a rectangle in viewport coordinates to pixel coordinates relative\n * to the viewer element.\n * @param {OpenSeadragon.Rect} rectangle the rectangle to convert\n * @returns {OpenSeadragon.Rect} the converted rectangle\n */\n viewportToViewerElementRectangle: function(rectangle) {\n return $.Rect.fromSummits(\n this.pixelFromPoint(rectangle.getTopLeft(), true),\n this.pixelFromPoint(rectangle.getTopRight(), true),\n this.pixelFromPoint(rectangle.getBottomLeft(), true)\n );\n },\n\n /**\n * Convert pixel coordinates relative to the window to viewport coordinates.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n windowToViewportCoordinates: function(pixel) {\n $.console.assert(this.viewer,\n \"[Viewport.windowToViewportCoordinates] the viewport must have a viewer.\");\n var viewerCoordinates = pixel.minus(\n $.getElementPosition(this.viewer.element));\n return this.viewerElementToViewportCoordinates(viewerCoordinates);\n },\n\n /**\n * Convert viewport coordinates to pixel coordinates relative to the window.\n * @param {OpenSeadragon.Point} point\n * @returns {OpenSeadragon.Point}\n */\n viewportToWindowCoordinates: function(point) {\n $.console.assert(this.viewer,\n \"[Viewport.viewportToWindowCoordinates] the viewport must have a viewer.\");\n var viewerCoordinates = this.viewportToViewerElementCoordinates(point);\n return viewerCoordinates.plus(\n $.getElementPosition(this.viewer.element));\n },\n\n /**\n * Convert a viewport zoom to an image zoom.\n * Image zoom: ratio of the original image size to displayed image size.\n * 1 means original image size, 0.5 half size...\n * Viewport zoom: ratio of the displayed image's width to viewport's width.\n * 1 means identical width, 2 means image's width is twice the viewport's width...\n * Note: not accurate with multi-image.\n * @function\n * @param {Number} viewportZoom The viewport zoom\n * target zoom.\n * @returns {Number} imageZoom The image zoom\n */\n viewportToImageZoom: function(viewportZoom) {\n if (this.viewer) {\n var count = this.viewer.world.getItemCount();\n if (count > 1) {\n $.console.error('[Viewport.viewportToImageZoom] is not ' +\n 'accurate with multi-image.');\n } else if (count === 1) {\n // It is better to use TiledImage.viewportToImageZoom\n // because this._contentBoundsNoRotate can not be relied on\n // with clipping.\n var item = this.viewer.world.getItemAt(0);\n return item.viewportToImageZoom(viewportZoom);\n }\n }\n\n var imageWidth = this._contentSizeNoRotate.x;\n var containerWidth = this._containerInnerSize.x;\n var scale = this._contentBoundsNoRotate.width;\n var viewportToImageZoomRatio = (containerWidth / imageWidth) * scale;\n return viewportZoom * viewportToImageZoomRatio;\n },\n\n /**\n * Convert an image zoom to a viewport zoom.\n * Image zoom: ratio of the original image size to displayed image size.\n * 1 means original image size, 0.5 half size...\n * Viewport zoom: ratio of the displayed image's width to viewport's width.\n * 1 means identical width, 2 means image's width is twice the viewport's width...\n * Note: not accurate with multi-image.\n * @function\n * @param {Number} imageZoom The image zoom\n * target zoom.\n * @returns {Number} viewportZoom The viewport zoom\n */\n imageToViewportZoom: function(imageZoom) {\n if (this.viewer) {\n var count = this.viewer.world.getItemCount();\n if (count > 1) {\n $.console.error('[Viewport.imageToViewportZoom] is not accurate ' +\n 'with multi-image.');\n } else if (count === 1) {\n // It is better to use TiledImage.imageToViewportZoom\n // because this._contentBoundsNoRotate can not be relied on\n // with clipping.\n var item = this.viewer.world.getItemAt(0);\n return item.imageToViewportZoom(imageZoom);\n }\n }\n\n var imageWidth = this._contentSizeNoRotate.x;\n var containerWidth = this._containerInnerSize.x;\n var scale = this._contentBoundsNoRotate.width;\n var viewportToImageZoomRatio = (imageWidth / containerWidth) / scale;\n return imageZoom * viewportToImageZoomRatio;\n }\n};\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - TiledImage\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * You shouldn't have to create a TiledImage directly; use {@link OpenSeadragon.Viewer#open}\n * or {@link OpenSeadragon.Viewer#addTiledImage} instead.\n * @class TiledImage\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.EventSource\n * @classdesc Handles rendering of tiles for an {@link OpenSeadragon.Viewer}.\n * A new instance is created for each TileSource opened.\n * @param {Object} options - Configuration for this TiledImage.\n * @param {OpenSeadragon.TileSource} options.source - The TileSource that defines this TiledImage.\n * @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this TiledImage.\n * @param {OpenSeadragon.TileCache} options.tileCache - The TileCache for this TiledImage to use.\n * @param {OpenSeadragon.Drawer} options.drawer - The Drawer for this TiledImage to draw onto.\n * @param {OpenSeadragon.ImageLoader} options.imageLoader - The ImageLoader for this TiledImage to use.\n * @param {Number} [options.x=0] - Left position, in viewport coordinates.\n * @param {Number} [options.y=0] - Top position, in viewport coordinates.\n * @param {Number} [options.width=1] - Width, in viewport coordinates.\n * @param {Number} [options.height] - Height, in viewport coordinates.\n * @param {OpenSeadragon.Rect} [options.fitBounds] The bounds in viewport coordinates\n * to fit the image into. If specified, x, y, width and height get ignored.\n * @param {OpenSeadragon.Placement} [options.fitBoundsPlacement=OpenSeadragon.Placement.CENTER]\n * How to anchor the image in the bounds if options.fitBounds is set.\n * @param {OpenSeadragon.Rect} [options.clip] - An area, in image pixels, to clip to\n * (portions of the image outside of this area will not be visible). Only works on\n * browsers that support the HTML5 canvas.\n * @param {Number} [options.springStiffness] - See {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.animationTime] - See {@link OpenSeadragon.Options}.\n * @param {Number} [options.minZoomImageRatio] - See {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.wrapHorizontal] - See {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.wrapVertical] - See {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.immediateRender] - See {@link OpenSeadragon.Options}.\n * @param {Number} [options.blendTime] - See {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.alwaysBlend] - See {@link OpenSeadragon.Options}.\n * @param {Number} [options.minPixelRatio] - See {@link OpenSeadragon.Options}.\n * @param {Number} [options.smoothTileEdgesMinZoom] - See {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.iOSDevice] - See {@link OpenSeadragon.Options}.\n * @param {Number} [options.opacity=1] - Set to draw at proportional opacity. If zero, images will not draw.\n * @param {Boolean} [options.preload=false] - Set true to load even when the image is hidden by zero opacity.\n * @param {String} [options.compositeOperation] - How the image is composited onto other images; see compositeOperation in {@link OpenSeadragon.Options} for possible values.\n * @param {Boolean} [options.debugMode] - See {@link OpenSeadragon.Options}.\n * @param {String|CanvasGradient|CanvasPattern|Function} [options.placeholderFillStyle] - See {@link OpenSeadragon.Options}.\n * @param {String|Boolean} [options.crossOriginPolicy] - See {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.ajaxWithCredentials] - See {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.loadTilesWithAjax]\n * Whether to load tile data using AJAX requests.\n * Defaults to the setting in {@link OpenSeadragon.Options}.\n * @param {Object} [options.ajaxHeaders={}]\n * A set of headers to include when making tile AJAX requests.\n */\n$.TiledImage = function( options ) {\n var _this = this;\n\n $.console.assert( options.tileCache, \"[TiledImage] options.tileCache is required\" );\n $.console.assert( options.drawer, \"[TiledImage] options.drawer is required\" );\n $.console.assert( options.viewer, \"[TiledImage] options.viewer is required\" );\n $.console.assert( options.imageLoader, \"[TiledImage] options.imageLoader is required\" );\n $.console.assert( options.source, \"[TiledImage] options.source is required\" );\n $.console.assert(!options.clip || options.clip instanceof $.Rect,\n \"[TiledImage] options.clip must be an OpenSeadragon.Rect if present\");\n\n $.EventSource.call( this );\n\n this._tileCache = options.tileCache;\n delete options.tileCache;\n\n this._drawer = options.drawer;\n delete options.drawer;\n\n this._imageLoader = options.imageLoader;\n delete options.imageLoader;\n\n if (options.clip instanceof $.Rect) {\n this._clip = options.clip.clone();\n }\n\n delete options.clip;\n\n var x = options.x || 0;\n delete options.x;\n var y = options.y || 0;\n delete options.y;\n\n // Ratio of zoomable image height to width.\n this.normHeight = options.source.dimensions.y / options.source.dimensions.x;\n this.contentAspectX = options.source.dimensions.x / options.source.dimensions.y;\n\n var scale = 1;\n if ( options.width ) {\n scale = options.width;\n delete options.width;\n\n if ( options.height ) {\n $.console.error( \"specifying both width and height to a tiledImage is not supported\" );\n delete options.height;\n }\n } else if ( options.height ) {\n scale = options.height / this.normHeight;\n delete options.height;\n }\n\n var fitBounds = options.fitBounds;\n delete options.fitBounds;\n var fitBoundsPlacement = options.fitBoundsPlacement || OpenSeadragon.Placement.CENTER;\n delete options.fitBoundsPlacement;\n\n var degrees = options.degrees || 0;\n delete options.degrees;\n\n $.extend( true, this, {\n\n //internal state properties\n viewer: null,\n tilesMatrix: {}, // A '3d' dictionary [level][x][y] --> Tile.\n coverage: {}, // A '3d' dictionary [level][x][y] --> Boolean; shows what areas have been drawn.\n loadingCoverage: {}, // A '3d' dictionary [level][x][y] --> Boolean; shows what areas are loaded or are being loaded/blended.\n lastDrawn: [], // An unordered list of Tiles drawn last frame.\n lastResetTime: 0, // Last time for which the tiledImage was reset.\n _midDraw: false, // Is the tiledImage currently updating the viewport?\n _needsDraw: true, // Does the tiledImage need to update the viewport again?\n _hasOpaqueTile: false, // Do we have even one fully opaque tile?\n _tilesLoading: 0, // The number of pending tile requests.\n //configurable settings\n springStiffness: $.DEFAULT_SETTINGS.springStiffness,\n animationTime: $.DEFAULT_SETTINGS.animationTime,\n minZoomImageRatio: $.DEFAULT_SETTINGS.minZoomImageRatio,\n wrapHorizontal: $.DEFAULT_SETTINGS.wrapHorizontal,\n wrapVertical: $.DEFAULT_SETTINGS.wrapVertical,\n immediateRender: $.DEFAULT_SETTINGS.immediateRender,\n blendTime: $.DEFAULT_SETTINGS.blendTime,\n alwaysBlend: $.DEFAULT_SETTINGS.alwaysBlend,\n minPixelRatio: $.DEFAULT_SETTINGS.minPixelRatio,\n smoothTileEdgesMinZoom: $.DEFAULT_SETTINGS.smoothTileEdgesMinZoom,\n iOSDevice: $.DEFAULT_SETTINGS.iOSDevice,\n debugMode: $.DEFAULT_SETTINGS.debugMode,\n crossOriginPolicy: $.DEFAULT_SETTINGS.crossOriginPolicy,\n ajaxWithCredentials: $.DEFAULT_SETTINGS.ajaxWithCredentials,\n placeholderFillStyle: $.DEFAULT_SETTINGS.placeholderFillStyle,\n opacity: $.DEFAULT_SETTINGS.opacity,\n preload: $.DEFAULT_SETTINGS.preload,\n compositeOperation: $.DEFAULT_SETTINGS.compositeOperation\n }, options );\n\n this._preload = this.preload;\n delete this.preload;\n\n this._fullyLoaded = false;\n\n this._xSpring = new $.Spring({\n initial: x,\n springStiffness: this.springStiffness,\n animationTime: this.animationTime\n });\n\n this._ySpring = new $.Spring({\n initial: y,\n springStiffness: this.springStiffness,\n animationTime: this.animationTime\n });\n\n this._scaleSpring = new $.Spring({\n initial: scale,\n springStiffness: this.springStiffness,\n animationTime: this.animationTime\n });\n\n this._degreesSpring = new $.Spring({\n initial: degrees,\n springStiffness: this.springStiffness,\n animationTime: this.animationTime\n });\n\n this._updateForScale();\n\n if (fitBounds) {\n this.fitBounds(fitBounds, fitBoundsPlacement, true);\n }\n\n // We need a callback to give image manipulation a chance to happen\n this._drawingHandler = function(args) {\n /**\n * This event is fired just before the tile is drawn giving the application a chance to alter the image.\n *\n * NOTE: This event is only fired when the drawer is using a <canvas>.\n *\n * @event tile-drawing\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {OpenSeadragon.Tile} tile - The Tile being drawn.\n * @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.\n * @property {OpenSeadragon.Tile} context - The HTML canvas context being drawn into.\n * @property {OpenSeadragon.Tile} rendered - The HTML canvas context containing the tile imagery.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.viewer.raiseEvent('tile-drawing', $.extend({\n tiledImage: _this\n }, args));\n };\n};\n\n$.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.TiledImage.prototype */{\n /**\n * @returns {Boolean} Whether the TiledImage needs to be drawn.\n */\n needsDraw: function() {\n return this._needsDraw;\n },\n\n /**\n * @returns {Boolean} Whether all tiles necessary for this TiledImage to draw at the current view have been loaded.\n */\n getFullyLoaded: function() {\n return this._fullyLoaded;\n },\n\n // private\n _setFullyLoaded: function(flag) {\n if (flag === this._fullyLoaded) {\n return;\n }\n\n this._fullyLoaded = flag;\n\n /**\n * Fired when the TiledImage's \"fully loaded\" flag (whether all tiles necessary for this TiledImage\n * to draw at the current view have been loaded) changes.\n *\n * @event fully-loaded-change\n * @memberof OpenSeadragon.TiledImage\n * @type {object}\n * @property {Boolean} fullyLoaded - The new \"fully loaded\" value.\n * @property {OpenSeadragon.TiledImage} eventSource - A reference to the TiledImage which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent('fully-loaded-change', {\n fullyLoaded: this._fullyLoaded\n });\n },\n\n /**\n * Clears all tiles and triggers an update on the next call to\n * {@link OpenSeadragon.TiledImage#update}.\n */\n reset: function() {\n this._tileCache.clearTilesFor(this);\n this.lastResetTime = $.now();\n this._needsDraw = true;\n },\n\n /**\n * Updates the TiledImage's bounds, animating if needed.\n * @returns {Boolean} Whether the TiledImage animated.\n */\n update: function() {\n var xUpdated = this._xSpring.update();\n var yUpdated = this._ySpring.update();\n var scaleUpdated = this._scaleSpring.update();\n var degreesUpdated = this._degreesSpring.update();\n\n if (xUpdated || yUpdated || scaleUpdated || degreesUpdated) {\n this._updateForScale();\n this._needsDraw = true;\n return true;\n }\n\n return false;\n },\n\n /**\n * Draws the TiledImage to its Drawer.\n */\n draw: function() {\n if (this.opacity !== 0 || this._preload) {\n this._midDraw = true;\n this._updateViewport();\n this._midDraw = false;\n }\n },\n\n /**\n * Destroy the TiledImage (unload current loaded tiles).\n */\n destroy: function() {\n this.reset();\n },\n\n /**\n * Get this TiledImage's bounds in viewport coordinates.\n * @param {Boolean} [current=false] - Pass true for the current location;\n * false for target location.\n * @returns {OpenSeadragon.Rect} This TiledImage's bounds in viewport coordinates.\n */\n getBounds: function(current) {\n return this.getBoundsNoRotate(current)\n .rotate(this.getRotation(current), this._getRotationPoint(current));\n },\n\n /**\n * Get this TiledImage's bounds in viewport coordinates without taking\n * rotation into account.\n * @param {Boolean} [current=false] - Pass true for the current location;\n * false for target location.\n * @returns {OpenSeadragon.Rect} This TiledImage's bounds in viewport coordinates.\n */\n getBoundsNoRotate: function(current) {\n return current ?\n new $.Rect(\n this._xSpring.current.value,\n this._ySpring.current.value,\n this._worldWidthCurrent,\n this._worldHeightCurrent) :\n new $.Rect(\n this._xSpring.target.value,\n this._ySpring.target.value,\n this._worldWidthTarget,\n this._worldHeightTarget);\n },\n\n // deprecated\n getWorldBounds: function() {\n $.console.error('[TiledImage.getWorldBounds] is deprecated; use TiledImage.getBounds instead');\n return this.getBounds();\n },\n\n /**\n * Get the bounds of the displayed part of the tiled image.\n * @param {Boolean} [current=false] Pass true for the current location,\n * false for the target location.\n * @returns {$.Rect} The clipped bounds in viewport coordinates.\n */\n getClippedBounds: function(current) {\n var bounds = this.getBoundsNoRotate(current);\n if (this._clip) {\n var worldWidth = current ?\n this._worldWidthCurrent : this._worldWidthTarget;\n var ratio = worldWidth / this.source.dimensions.x;\n var clip = this._clip.times(ratio);\n bounds = new $.Rect(\n bounds.x + clip.x,\n bounds.y + clip.y,\n clip.width,\n clip.height);\n }\n return bounds.rotate(this.getRotation(current), this._getRotationPoint(current));\n },\n\n /**\n * @returns {OpenSeadragon.Point} This TiledImage's content size, in original pixels.\n */\n getContentSize: function() {\n return new $.Point(this.source.dimensions.x, this.source.dimensions.y);\n },\n\n // private\n _viewportToImageDelta: function( viewerX, viewerY, current ) {\n var scale = (current ? this._scaleSpring.current.value : this._scaleSpring.target.value);\n return new $.Point(viewerX * (this.source.dimensions.x / scale),\n viewerY * ((this.source.dimensions.y * this.contentAspectX) / scale));\n },\n\n /**\n * Translates from OpenSeadragon viewer coordinate system to image coordinate system.\n * This method can be called either by passing X,Y coordinates or an {@link OpenSeadragon.Point}.\n * @param {Number|OpenSeadragon.Point} viewerX - The X coordinate or point in viewport coordinate system.\n * @param {Number} [viewerY] - The Y coordinate in viewport coordinate system.\n * @param {Boolean} [current=false] - Pass true to use the current location; false for target location.\n * @return {OpenSeadragon.Point} A point representing the coordinates in the image.\n */\n viewportToImageCoordinates: function(viewerX, viewerY, current) {\n var point;\n if (viewerX instanceof $.Point) {\n //they passed a point instead of individual components\n current = viewerY;\n point = viewerX;\n } else {\n point = new $.Point(viewerX, viewerY);\n }\n\n point = point.rotate(-this.getRotation(current), this._getRotationPoint(current));\n return current ?\n this._viewportToImageDelta(\n point.x - this._xSpring.current.value,\n point.y - this._ySpring.current.value) :\n this._viewportToImageDelta(\n point.x - this._xSpring.target.value,\n point.y - this._ySpring.target.value);\n },\n\n // private\n _imageToViewportDelta: function( imageX, imageY, current ) {\n var scale = (current ? this._scaleSpring.current.value : this._scaleSpring.target.value);\n return new $.Point((imageX / this.source.dimensions.x) * scale,\n (imageY / this.source.dimensions.y / this.contentAspectX) * scale);\n },\n\n /**\n * Translates from image coordinate system to OpenSeadragon viewer coordinate system\n * This method can be called either by passing X,Y coordinates or an {@link OpenSeadragon.Point}.\n * @param {Number|OpenSeadragon.Point} imageX - The X coordinate or point in image coordinate system.\n * @param {Number} [imageY] - The Y coordinate in image coordinate system.\n * @param {Boolean} [current=false] - Pass true to use the current location; false for target location.\n * @return {OpenSeadragon.Point} A point representing the coordinates in the viewport.\n */\n imageToViewportCoordinates: function(imageX, imageY, current) {\n if (imageX instanceof $.Point) {\n //they passed a point instead of individual components\n current = imageY;\n imageY = imageX.y;\n imageX = imageX.x;\n }\n\n var point = this._imageToViewportDelta(imageX, imageY);\n if (current) {\n point.x += this._xSpring.current.value;\n point.y += this._ySpring.current.value;\n } else {\n point.x += this._xSpring.target.value;\n point.y += this._ySpring.target.value;\n }\n\n return point.rotate(this.getRotation(current), this._getRotationPoint(current));\n },\n\n /**\n * Translates from a rectangle which describes a portion of the image in\n * pixel coordinates to OpenSeadragon viewport rectangle coordinates.\n * This method can be called either by passing X,Y,width,height or an {@link OpenSeadragon.Rect}.\n * @param {Number|OpenSeadragon.Rect} imageX - The left coordinate or rectangle in image coordinate system.\n * @param {Number} [imageY] - The top coordinate in image coordinate system.\n * @param {Number} [pixelWidth] - The width in pixel of the rectangle.\n * @param {Number} [pixelHeight] - The height in pixel of the rectangle.\n * @param {Boolean} [current=false] - Pass true to use the current location; false for target location.\n * @return {OpenSeadragon.Rect} A rect representing the coordinates in the viewport.\n */\n imageToViewportRectangle: function(imageX, imageY, pixelWidth, pixelHeight, current) {\n var rect = imageX;\n if (rect instanceof $.Rect) {\n //they passed a rect instead of individual components\n current = imageY;\n } else {\n rect = new $.Rect(imageX, imageY, pixelWidth, pixelHeight);\n }\n\n var coordA = this.imageToViewportCoordinates(rect.getTopLeft(), current);\n var coordB = this._imageToViewportDelta(rect.width, rect.height, current);\n\n return new $.Rect(\n coordA.x,\n coordA.y,\n coordB.x,\n coordB.y,\n rect.degrees + this.getRotation(current)\n );\n },\n\n /**\n * Translates from a rectangle which describes a portion of\n * the viewport in point coordinates to image rectangle coordinates.\n * This method can be called either by passing X,Y,width,height or an {@link OpenSeadragon.Rect}.\n * @param {Number|OpenSeadragon.Rect} viewerX - The left coordinate or rectangle in viewport coordinate system.\n * @param {Number} [viewerY] - The top coordinate in viewport coordinate system.\n * @param {Number} [pointWidth] - The width in viewport coordinate system.\n * @param {Number} [pointHeight] - The height in viewport coordinate system.\n * @param {Boolean} [current=false] - Pass true to use the current location; false for target location.\n * @return {OpenSeadragon.Rect} A rect representing the coordinates in the image.\n */\n viewportToImageRectangle: function( viewerX, viewerY, pointWidth, pointHeight, current ) {\n var rect = viewerX;\n if (viewerX instanceof $.Rect) {\n //they passed a rect instead of individual components\n current = viewerY;\n } else {\n rect = new $.Rect(viewerX, viewerY, pointWidth, pointHeight);\n }\n\n var coordA = this.viewportToImageCoordinates(rect.getTopLeft(), current);\n var coordB = this._viewportToImageDelta(rect.width, rect.height, current);\n\n return new $.Rect(\n coordA.x,\n coordA.y,\n coordB.x,\n coordB.y,\n rect.degrees - this.getRotation(current)\n );\n },\n\n /**\n * Convert pixel coordinates relative to the viewer element to image\n * coordinates.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n viewerElementToImageCoordinates: function( pixel ) {\n var point = this.viewport.pointFromPixel( pixel, true );\n return this.viewportToImageCoordinates( point );\n },\n\n /**\n * Convert pixel coordinates relative to the image to\n * viewer element coordinates.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n imageToViewerElementCoordinates: function( pixel ) {\n var point = this.imageToViewportCoordinates( pixel );\n return this.viewport.pixelFromPoint( point, true );\n },\n\n /**\n * Convert pixel coordinates relative to the window to image coordinates.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n windowToImageCoordinates: function( pixel ) {\n var viewerCoordinates = pixel.minus(\n OpenSeadragon.getElementPosition( this.viewer.element ));\n return this.viewerElementToImageCoordinates( viewerCoordinates );\n },\n\n /**\n * Convert image coordinates to pixel coordinates relative to the window.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n imageToWindowCoordinates: function( pixel ) {\n var viewerCoordinates = this.imageToViewerElementCoordinates( pixel );\n return viewerCoordinates.plus(\n OpenSeadragon.getElementPosition( this.viewer.element ));\n },\n\n // private\n // Convert rectangle in viewport coordinates to this tiled image point\n // coordinates (x in [0, 1] and y in [0, aspectRatio])\n _viewportToTiledImageRectangle: function(rect) {\n var scale = this._scaleSpring.current.value;\n rect = rect.rotate(-this.getRotation(true), this._getRotationPoint(true));\n return new $.Rect(\n (rect.x - this._xSpring.current.value) / scale,\n (rect.y - this._ySpring.current.value) / scale,\n rect.width / scale,\n rect.height / scale,\n rect.degrees);\n },\n\n /**\n * Convert a viewport zoom to an image zoom.\n * Image zoom: ratio of the original image size to displayed image size.\n * 1 means original image size, 0.5 half size...\n * Viewport zoom: ratio of the displayed image's width to viewport's width.\n * 1 means identical width, 2 means image's width is twice the viewport's width...\n * @function\n * @param {Number} viewportZoom The viewport zoom\n * @returns {Number} imageZoom The image zoom\n */\n viewportToImageZoom: function( viewportZoom ) {\n var ratio = this._scaleSpring.current.value *\n this.viewport._containerInnerSize.x / this.source.dimensions.x;\n return ratio * viewportZoom;\n },\n\n /**\n * Convert an image zoom to a viewport zoom.\n * Image zoom: ratio of the original image size to displayed image size.\n * 1 means original image size, 0.5 half size...\n * Viewport zoom: ratio of the displayed image's width to viewport's width.\n * 1 means identical width, 2 means image's width is twice the viewport's width...\n * Note: not accurate with multi-image.\n * @function\n * @param {Number} imageZoom The image zoom\n * @returns {Number} viewportZoom The viewport zoom\n */\n imageToViewportZoom: function( imageZoom ) {\n var ratio = this._scaleSpring.current.value *\n this.viewport._containerInnerSize.x / this.source.dimensions.x;\n return imageZoom / ratio;\n },\n\n /**\n * Sets the TiledImage's position in the world.\n * @param {OpenSeadragon.Point} position - The new position, in viewport coordinates.\n * @param {Boolean} [immediately=false] - Whether to animate to the new position or snap immediately.\n * @fires OpenSeadragon.TiledImage.event:bounds-change\n */\n setPosition: function(position, immediately) {\n var sameTarget = (this._xSpring.target.value === position.x &&\n this._ySpring.target.value === position.y);\n\n if (immediately) {\n if (sameTarget && this._xSpring.current.value === position.x &&\n this._ySpring.current.value === position.y) {\n return;\n }\n\n this._xSpring.resetTo(position.x);\n this._ySpring.resetTo(position.y);\n this._needsDraw = true;\n } else {\n if (sameTarget) {\n return;\n }\n\n this._xSpring.springTo(position.x);\n this._ySpring.springTo(position.y);\n this._needsDraw = true;\n }\n\n if (!sameTarget) {\n this._raiseBoundsChange();\n }\n },\n\n /**\n * Sets the TiledImage's width in the world, adjusting the height to match based on aspect ratio.\n * @param {Number} width - The new width, in viewport coordinates.\n * @param {Boolean} [immediately=false] - Whether to animate to the new size or snap immediately.\n * @fires OpenSeadragon.TiledImage.event:bounds-change\n */\n setWidth: function(width, immediately) {\n this._setScale(width, immediately);\n },\n\n /**\n * Sets the TiledImage's height in the world, adjusting the width to match based on aspect ratio.\n * @param {Number} height - The new height, in viewport coordinates.\n * @param {Boolean} [immediately=false] - Whether to animate to the new size or snap immediately.\n * @fires OpenSeadragon.TiledImage.event:bounds-change\n */\n setHeight: function(height, immediately) {\n this._setScale(height / this.normHeight, immediately);\n },\n\n /**\n * Positions and scales the TiledImage to fit in the specified bounds.\n * Note: this method fires OpenSeadragon.TiledImage.event:bounds-change\n * twice\n * @param {OpenSeadragon.Rect} bounds The bounds to fit the image into.\n * @param {OpenSeadragon.Placement} [anchor=OpenSeadragon.Placement.CENTER]\n * How to anchor the image in the bounds.\n * @param {Boolean} [immediately=false] Whether to animate to the new size\n * or snap immediately.\n * @fires OpenSeadragon.TiledImage.event:bounds-change\n */\n fitBounds: function(bounds, anchor, immediately) {\n anchor = anchor || $.Placement.CENTER;\n var anchorProperties = $.Placement.properties[anchor];\n var aspectRatio = this.contentAspectX;\n var xOffset = 0;\n var yOffset = 0;\n var displayedWidthRatio = 1;\n var displayedHeightRatio = 1;\n if (this._clip) {\n aspectRatio = this._clip.getAspectRatio();\n displayedWidthRatio = this._clip.width / this.source.dimensions.x;\n displayedHeightRatio = this._clip.height / this.source.dimensions.y;\n if (bounds.getAspectRatio() > aspectRatio) {\n xOffset = this._clip.x / this._clip.height * bounds.height;\n yOffset = this._clip.y / this._clip.height * bounds.height;\n } else {\n xOffset = this._clip.x / this._clip.width * bounds.width;\n yOffset = this._clip.y / this._clip.width * bounds.width;\n }\n }\n\n if (bounds.getAspectRatio() > aspectRatio) {\n // We will have margins on the X axis\n var height = bounds.height / displayedHeightRatio;\n var marginLeft = 0;\n if (anchorProperties.isHorizontallyCentered) {\n marginLeft = (bounds.width - bounds.height * aspectRatio) / 2;\n } else if (anchorProperties.isRight) {\n marginLeft = bounds.width - bounds.height * aspectRatio;\n }\n this.setPosition(\n new $.Point(bounds.x - xOffset + marginLeft, bounds.y - yOffset),\n immediately);\n this.setHeight(height, immediately);\n } else {\n // We will have margins on the Y axis\n var width = bounds.width / displayedWidthRatio;\n var marginTop = 0;\n if (anchorProperties.isVerticallyCentered) {\n marginTop = (bounds.height - bounds.width / aspectRatio) / 2;\n } else if (anchorProperties.isBottom) {\n marginTop = bounds.height - bounds.width / aspectRatio;\n }\n this.setPosition(\n new $.Point(bounds.x - xOffset, bounds.y - yOffset + marginTop),\n immediately);\n this.setWidth(width, immediately);\n }\n },\n\n /**\n * @returns {OpenSeadragon.Rect|null} The TiledImage's current clip rectangle,\n * in image pixels, or null if none.\n */\n getClip: function() {\n if (this._clip) {\n return this._clip.clone();\n }\n\n return null;\n },\n\n /**\n * @param {OpenSeadragon.Rect|null} newClip - An area, in image pixels, to clip to\n * (portions of the image outside of this area will not be visible). Only works on\n * browsers that support the HTML5 canvas.\n * @fires OpenSeadragon.TiledImage.event:clip-change\n */\n setClip: function(newClip) {\n $.console.assert(!newClip || newClip instanceof $.Rect,\n \"[TiledImage.setClip] newClip must be an OpenSeadragon.Rect or null\");\n\n if (newClip instanceof $.Rect) {\n this._clip = newClip.clone();\n } else {\n this._clip = null;\n }\n\n this._needsDraw = true;\n /**\n * Raised when the TiledImage's clip is changed.\n * @event clip-change\n * @memberOf OpenSeadragon.TiledImage\n * @type {object}\n * @property {OpenSeadragon.TiledImage} eventSource - A reference to the\n * TiledImage which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent('clip-change');\n },\n\n /**\n * @returns {Number} The TiledImage's current opacity.\n */\n getOpacity: function() {\n return this.opacity;\n },\n\n /**\n * @param {Number} opacity Opacity the tiled image should be drawn at.\n * @fires OpenSeadragon.TiledImage.event:opacity-change\n */\n setOpacity: function(opacity) {\n if (opacity === this.opacity) {\n return;\n }\n\n this.opacity = opacity;\n this._needsDraw = true;\n /**\n * Raised when the TiledImage's opacity is changed.\n * @event opacity-change\n * @memberOf OpenSeadragon.TiledImage\n * @type {object}\n * @property {Number} opacity - The new opacity value.\n * @property {OpenSeadragon.TiledImage} eventSource - A reference to the\n * TiledImage which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent('opacity-change', {\n opacity: this.opacity\n });\n },\n\n /**\n * @returns {Boolean} whether the tiledImage can load its tiles even when it has zero opacity.\n */\n getPreload: function() {\n return this._preload;\n },\n\n /**\n * Set true to load even when hidden. Set false to block loading when hidden.\n */\n setPreload: function(preload) {\n this._preload = !!preload;\n this._needsDraw = true;\n },\n\n /**\n * Get the rotation of this tiled image in degrees.\n * @param {Boolean} [current=false] True for current rotation, false for target.\n * @returns {Number} the rotation of this tiled image in degrees.\n */\n getRotation: function(current) {\n return current ?\n this._degreesSpring.current.value :\n this._degreesSpring.target.value;\n },\n\n /**\n * Set the current rotation of this tiled image in degrees.\n * @param {Number} degrees the rotation in degrees.\n * @param {Boolean} [immediately=false] Whether to animate to the new angle\n * or rotate immediately.\n * @fires OpenSeadragon.TiledImage.event:bounds-change\n */\n setRotation: function(degrees, immediately) {\n if (this._degreesSpring.target.value === degrees &&\n this._degreesSpring.isAtTargetValue()) {\n return;\n }\n if (immediately) {\n this._degreesSpring.resetTo(degrees);\n } else {\n this._degreesSpring.springTo(degrees);\n }\n this._needsDraw = true;\n this._raiseBoundsChange();\n },\n\n /**\n * Get the point around which this tiled image is rotated\n * @private\n * @param {Boolean} current True for current rotation point, false for target.\n * @returns {OpenSeadragon.Point}\n */\n _getRotationPoint: function(current) {\n return this.getBoundsNoRotate(current).getCenter();\n },\n\n /**\n * @returns {String} The TiledImage's current compositeOperation.\n */\n getCompositeOperation: function() {\n return this.compositeOperation;\n },\n\n /**\n * @param {String} compositeOperation the tiled image should be drawn with this globalCompositeOperation.\n * @fires OpenSeadragon.TiledImage.event:composite-operation-change\n */\n setCompositeOperation: function(compositeOperation) {\n if (compositeOperation === this.compositeOperation) {\n return;\n }\n\n this.compositeOperation = compositeOperation;\n this._needsDraw = true;\n /**\n * Raised when the TiledImage's opacity is changed.\n * @event composite-operation-change\n * @memberOf OpenSeadragon.TiledImage\n * @type {object}\n * @property {String} compositeOperation - The new compositeOperation value.\n * @property {OpenSeadragon.TiledImage} eventSource - A reference to the\n * TiledImage which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent('composite-operation-change', {\n compositeOperation: this.compositeOperation\n });\n },\n\n // private\n _setScale: function(scale, immediately) {\n var sameTarget = (this._scaleSpring.target.value === scale);\n if (immediately) {\n if (sameTarget && this._scaleSpring.current.value === scale) {\n return;\n }\n\n this._scaleSpring.resetTo(scale);\n this._updateForScale();\n this._needsDraw = true;\n } else {\n if (sameTarget) {\n return;\n }\n\n this._scaleSpring.springTo(scale);\n this._updateForScale();\n this._needsDraw = true;\n }\n\n if (!sameTarget) {\n this._raiseBoundsChange();\n }\n },\n\n // private\n _updateForScale: function() {\n this._worldWidthTarget = this._scaleSpring.target.value;\n this._worldHeightTarget = this.normHeight * this._scaleSpring.target.value;\n this._worldWidthCurrent = this._scaleSpring.current.value;\n this._worldHeightCurrent = this.normHeight * this._scaleSpring.current.value;\n },\n\n // private\n _raiseBoundsChange: function() {\n /**\n * Raised when the TiledImage's bounds are changed.\n * Note that this event is triggered only when the animation target is changed;\n * not for every frame of animation.\n * @event bounds-change\n * @memberOf OpenSeadragon.TiledImage\n * @type {object}\n * @property {OpenSeadragon.TiledImage} eventSource - A reference to the\n * TiledImage which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent('bounds-change');\n },\n\n // private\n _isBottomItem: function() {\n return this.viewer.world.getItemAt(0) === this;\n },\n\n // private\n _getLevelsInterval: function() {\n var lowestLevel = Math.max(\n this.source.minLevel,\n Math.floor(Math.log(this.minZoomImageRatio) / Math.log(2))\n );\n var currentZeroRatio = this.viewport.deltaPixelsFromPointsNoRotate(\n this.source.getPixelRatio(0), true).x *\n this._scaleSpring.current.value;\n var highestLevel = Math.min(\n Math.abs(this.source.maxLevel),\n Math.abs(Math.floor(\n Math.log(currentZeroRatio / this.minPixelRatio) / Math.log(2)\n ))\n );\n\n // Calculations for the interval of levels to draw\n // can return invalid intervals; fix that here if necessary\n lowestLevel = Math.min(lowestLevel, highestLevel);\n return {\n lowestLevel: lowestLevel,\n highestLevel: highestLevel\n };\n },\n\n /**\n * @private\n * @inner\n * Pretty much every other line in this needs to be documented so it's clear\n * how each piece of this routine contributes to the drawing process. That's\n * why there are so many TODO's inside this function.\n */\n _updateViewport: function() {\n this._needsDraw = false;\n this._tilesLoading = 0;\n this.loadingCoverage = {};\n\n // Reset tile's internal drawn state\n while (this.lastDrawn.length > 0) {\n var tile = this.lastDrawn.pop();\n tile.beingDrawn = false;\n }\n\n var viewport = this.viewport;\n var drawArea = this._viewportToTiledImageRectangle(\n viewport.getBoundsWithMargins(true));\n\n if (!this.wrapHorizontal && !this.wrapVertical) {\n var tiledImageBounds = this._viewportToTiledImageRectangle(\n this.getClippedBounds(true));\n drawArea = drawArea.intersection(tiledImageBounds);\n if (drawArea === null) {\n return;\n }\n }\n\n var levelsInterval = this._getLevelsInterval();\n var lowestLevel = levelsInterval.lowestLevel;\n var highestLevel = levelsInterval.highestLevel;\n var bestTile = null;\n var haveDrawn = false;\n var currentTime = $.now();\n\n // Update any level that will be drawn\n for (var level = highestLevel; level >= lowestLevel; level--) {\n var drawLevel = false;\n\n //Avoid calculations for draw if we have already drawn this\n var currentRenderPixelRatio = viewport.deltaPixelsFromPointsNoRotate(\n this.source.getPixelRatio(level),\n true\n ).x * this._scaleSpring.current.value;\n\n if (level === lowestLevel ||\n (!haveDrawn && currentRenderPixelRatio >= this.minPixelRatio)) {\n drawLevel = true;\n haveDrawn = true;\n } else if (!haveDrawn) {\n continue;\n }\n\n //Perform calculations for draw if we haven't drawn this\n var targetRenderPixelRatio = viewport.deltaPixelsFromPointsNoRotate(\n this.source.getPixelRatio(level),\n false\n ).x * this._scaleSpring.current.value;\n\n var targetZeroRatio = viewport.deltaPixelsFromPointsNoRotate(\n this.source.getPixelRatio(\n Math.max(\n this.source.getClosestLevel(),\n 0\n )\n ),\n false\n ).x * this._scaleSpring.current.value;\n\n var optimalRatio = this.immediateRender ? 1 : targetZeroRatio;\n var levelOpacity = Math.min(1, (currentRenderPixelRatio - 0.5) / 0.5);\n var levelVisibility = optimalRatio / Math.abs(\n optimalRatio - targetRenderPixelRatio\n );\n\n // Update the level and keep track of 'best' tile to load\n bestTile = updateLevel(\n this,\n haveDrawn,\n drawLevel,\n level,\n levelOpacity,\n levelVisibility,\n drawArea,\n currentTime,\n bestTile\n );\n\n // Stop the loop if lower-res tiles would all be covered by\n // already drawn tiles\n if (providesCoverage(this.coverage, level)) {\n break;\n }\n }\n\n // Perform the actual drawing\n drawTiles(this, this.lastDrawn);\n\n // Load the new 'best' tile\n if (bestTile && !bestTile.context2D) {\n loadTile(this, bestTile, currentTime);\n this._needsDraw = true;\n this._setFullyLoaded(false);\n } else {\n this._setFullyLoaded(this._tilesLoading === 0);\n }\n },\n\n // private\n _getCornerTiles: function(level, topLeftBound, bottomRightBound) {\n var leftX;\n var rightX;\n if (this.wrapHorizontal) {\n leftX = $.positiveModulo(topLeftBound.x, 1);\n rightX = $.positiveModulo(bottomRightBound.x, 1);\n } else {\n leftX = Math.max(0, topLeftBound.x);\n rightX = Math.min(1, bottomRightBound.x);\n }\n var topY;\n var bottomY;\n var aspectRatio = 1 / this.source.aspectRatio;\n if (this.wrapVertical) {\n topY = $.positiveModulo(topLeftBound.y, aspectRatio);\n bottomY = $.positiveModulo(bottomRightBound.y, aspectRatio);\n } else {\n topY = Math.max(0, topLeftBound.y);\n bottomY = Math.min(aspectRatio, bottomRightBound.y);\n }\n\n var topLeftTile = this.source.getTileAtPoint(level, new $.Point(leftX, topY));\n var bottomRightTile = this.source.getTileAtPoint(level, new $.Point(rightX, bottomY));\n var numTiles = this.source.getNumTiles(level);\n\n if (this.wrapHorizontal) {\n topLeftTile.x += numTiles.x * Math.floor(topLeftBound.x);\n bottomRightTile.x += numTiles.x * Math.floor(bottomRightBound.x);\n }\n if (this.wrapVertical) {\n topLeftTile.y += numTiles.y * Math.floor(topLeftBound.y / aspectRatio);\n bottomRightTile.y += numTiles.y * Math.floor(bottomRightBound.y / aspectRatio);\n }\n\n return {\n topLeft: topLeftTile,\n bottomRight: bottomRightTile,\n };\n }\n});\n\n/**\n * @private\n * @inner\n * Updates all tiles at a given resolution level.\n * @param {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.\n * @param {Boolean} haveDrawn\n * @param {Boolean} drawLevel\n * @param {Number} level\n * @param {Number} levelOpacity\n * @param {Number} levelVisibility\n * @param {OpenSeadragon.Point} viewportTL - The index of the most top-left visible tile.\n * @param {OpenSeadragon.Point} viewportBR - The index of the most bottom-right visible tile.\n * @param {Number} currentTime\n * @param {OpenSeadragon.Tile} best - The current \"best\" tile to draw.\n */\nfunction updateLevel(tiledImage, haveDrawn, drawLevel, level, levelOpacity,\n levelVisibility, drawArea, currentTime, best) {\n\n var topLeftBound = drawArea.getBoundingBox().getTopLeft();\n var bottomRightBound = drawArea.getBoundingBox().getBottomRight();\n\n if (tiledImage.viewer) {\n /**\n * - Needs documentation -\n *\n * @event update-level\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.\n * @property {Object} havedrawn\n * @property {Object} level\n * @property {Object} opacity\n * @property {Object} visibility\n * @property {OpenSeadragon.Rect} drawArea\n * @property {Object} topleft deprecated, use drawArea instead\n * @property {Object} bottomright deprecated, use drawArea instead\n * @property {Object} currenttime\n * @property {Object} best\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n tiledImage.viewer.raiseEvent('update-level', {\n tiledImage: tiledImage,\n havedrawn: haveDrawn,\n level: level,\n opacity: levelOpacity,\n visibility: levelVisibility,\n drawArea: drawArea,\n topleft: topLeftBound,\n bottomright: bottomRightBound,\n currenttime: currentTime,\n best: best\n });\n }\n\n resetCoverage(tiledImage.coverage, level);\n resetCoverage(tiledImage.loadingCoverage, level);\n\n //OK, a new drawing so do your calculations\n var cornerTiles = tiledImage._getCornerTiles(level, topLeftBound, bottomRightBound);\n var topLeftTile = cornerTiles.topLeft;\n var bottomRightTile = cornerTiles.bottomRight;\n var numberOfTiles = tiledImage.source.getNumTiles(level);\n\n var viewportCenter = tiledImage.viewport.pixelFromPoint(\n tiledImage.viewport.getCenter());\n for (var x = topLeftTile.x; x <= bottomRightTile.x; x++) {\n for (var y = topLeftTile.y; y <= bottomRightTile.y; y++) {\n\n // Optimisation disabled with wrapping because getTileBounds does not\n // work correctly with x and y outside of the number of tiles\n if (!tiledImage.wrapHorizontal && !tiledImage.wrapVertical) {\n var tileBounds = tiledImage.source.getTileBounds(level, x, y);\n if (drawArea.intersection(tileBounds) === null) {\n // This tile is outside of the viewport, no need to draw it\n continue;\n }\n }\n\n best = updateTile(\n tiledImage,\n drawLevel,\n haveDrawn,\n x, y,\n level,\n levelOpacity,\n levelVisibility,\n viewportCenter,\n numberOfTiles,\n currentTime,\n best\n );\n\n }\n }\n\n return best;\n}\n\n/**\n * @private\n * @inner\n * Update a single tile at a particular resolution level.\n * @param {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.\n * @param {Boolean} haveDrawn\n * @param {Boolean} drawLevel\n * @param {Number} x\n * @param {Number} y\n * @param {Number} level\n * @param {Number} levelOpacity\n * @param {Number} levelVisibility\n * @param {OpenSeadragon.Point} viewportCenter\n * @param {Number} numberOfTiles\n * @param {Number} currentTime\n * @param {OpenSeadragon.Tile} best - The current \"best\" tile to draw.\n */\nfunction updateTile( tiledImage, haveDrawn, drawLevel, x, y, level, levelOpacity, levelVisibility, viewportCenter, numberOfTiles, currentTime, best){\n\n var tile = getTile(\n x, y,\n level,\n tiledImage,\n tiledImage.source,\n tiledImage.tilesMatrix,\n currentTime,\n numberOfTiles,\n tiledImage._worldWidthCurrent,\n tiledImage._worldHeightCurrent\n ),\n drawTile = drawLevel;\n\n if( tiledImage.viewer ){\n /**\n * - Needs documentation -\n *\n * @event update-tile\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.\n * @property {OpenSeadragon.Tile} tile\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n tiledImage.viewer.raiseEvent( 'update-tile', {\n tiledImage: tiledImage,\n tile: tile\n });\n }\n\n setCoverage( tiledImage.coverage, level, x, y, false );\n\n var loadingCoverage = tile.loaded || tile.loading || isCovered(tiledImage.loadingCoverage, level, x, y);\n setCoverage(tiledImage.loadingCoverage, level, x, y, loadingCoverage);\n\n if ( !tile.exists ) {\n return best;\n }\n\n if ( haveDrawn && !drawTile ) {\n if ( isCovered( tiledImage.coverage, level, x, y ) ) {\n setCoverage( tiledImage.coverage, level, x, y, true );\n } else {\n drawTile = true;\n }\n }\n\n if ( !drawTile ) {\n return best;\n }\n\n positionTile(\n tile,\n tiledImage.source.tileOverlap,\n tiledImage.viewport,\n viewportCenter,\n levelVisibility,\n tiledImage\n );\n\n if (!tile.loaded) {\n if (tile.context2D) {\n setTileLoaded(tiledImage, tile);\n } else {\n var imageRecord = tiledImage._tileCache.getImageRecord(tile.cacheKey);\n if (imageRecord) {\n var image = imageRecord.getImage();\n setTileLoaded(tiledImage, tile, image);\n }\n }\n }\n\n if ( tile.loaded ) {\n var needsDraw = blendTile(\n tiledImage,\n tile,\n x, y,\n level,\n levelOpacity,\n currentTime\n );\n\n if ( needsDraw ) {\n tiledImage._needsDraw = true;\n }\n } else if ( tile.loading ) {\n // the tile is already in the download queue\n tiledImage._tilesLoading++;\n } else if (!loadingCoverage) {\n best = compareTiles( best, tile );\n }\n\n return best;\n}\n\n/**\n * @private\n * @inner\n * Obtains a tile at the given location.\n * @param {Number} x\n * @param {Number} y\n * @param {Number} level\n * @param {OpenSeadragon.TiledImage} tiledImage\n * @param {OpenSeadragon.TileSource} tileSource\n * @param {Object} tilesMatrix - A '3d' dictionary [level][x][y] --> Tile.\n * @param {Number} time\n * @param {Number} numTiles\n * @param {Number} worldWidth\n * @param {Number} worldHeight\n * @returns {OpenSeadragon.Tile}\n */\nfunction getTile(\n x, y,\n level,\n tiledImage,\n tileSource,\n tilesMatrix,\n time,\n numTiles,\n worldWidth,\n worldHeight\n) {\n var xMod,\n yMod,\n bounds,\n exists,\n url,\n ajaxHeaders,\n context2D,\n tile;\n\n if ( !tilesMatrix[ level ] ) {\n tilesMatrix[ level ] = {};\n }\n if ( !tilesMatrix[ level ][ x ] ) {\n tilesMatrix[ level ][ x ] = {};\n }\n\n if ( !tilesMatrix[ level ][ x ][ y ] ) {\n xMod = ( numTiles.x + ( x % numTiles.x ) ) % numTiles.x;\n yMod = ( numTiles.y + ( y % numTiles.y ) ) % numTiles.y;\n bounds = tileSource.getTileBounds( level, xMod, yMod );\n exists = tileSource.tileExists( level, xMod, yMod );\n url = tileSource.getTileUrl( level, xMod, yMod );\n\n // Headers are only applicable if loadTilesWithAjax is set\n if (tiledImage.loadTilesWithAjax) {\n ajaxHeaders = tileSource.getTileAjaxHeaders( level, xMod, yMod );\n // Combine tile AJAX headers with tiled image AJAX headers (if applicable)\n if ($.isPlainObject(tiledImage.ajaxHeaders)) {\n ajaxHeaders = $.extend({}, tiledImage.ajaxHeaders, ajaxHeaders);\n }\n } else {\n ajaxHeaders = null;\n }\n\n context2D = tileSource.getContext2D ?\n tileSource.getContext2D(level, xMod, yMod) : undefined;\n\n bounds.x += ( x - xMod ) / numTiles.x;\n bounds.y += (worldHeight / worldWidth) * (( y - yMod ) / numTiles.y);\n\n tile = new $.Tile(\n level,\n x,\n y,\n bounds,\n exists,\n url,\n context2D,\n tiledImage.loadTilesWithAjax,\n ajaxHeaders\n );\n\n if (xMod === numTiles.x - 1) {\n tile.isRightMost = true;\n }\n\n if (yMod === numTiles.y - 1) {\n tile.isBottomMost = true;\n }\n\n tilesMatrix[ level ][ x ][ y ] = tile;\n }\n\n tile = tilesMatrix[ level ][ x ][ y ];\n tile.lastTouchTime = time;\n\n return tile;\n}\n\n/**\n * @private\n * @inner\n * Dispatch a job to the ImageLoader to load the Image for a Tile.\n * @param {OpenSeadragon.TiledImage} tiledImage\n * @param {OpenSeadragon.Tile} tile\n * @param {Number} time\n */\nfunction loadTile( tiledImage, tile, time ) {\n tile.loading = true;\n tiledImage._imageLoader.addJob({\n src: tile.url,\n loadWithAjax: tile.loadWithAjax,\n ajaxHeaders: tile.ajaxHeaders,\n crossOriginPolicy: tiledImage.crossOriginPolicy,\n ajaxWithCredentials: tiledImage.ajaxWithCredentials,\n callback: function( image, errorMsg, tileRequest ){\n onTileLoad( tiledImage, tile, time, image, errorMsg, tileRequest );\n },\n abort: function() {\n tile.loading = false;\n }\n });\n}\n\n/**\n * @private\n * @inner\n * Callback fired when a Tile's Image finished downloading.\n * @param {OpenSeadragon.TiledImage} tiledImage\n * @param {OpenSeadragon.Tile} tile\n * @param {Number} time\n * @param {Image} image\n * @param {String} errorMsg\n * @param {XMLHttpRequest} tileRequest\n */\nfunction onTileLoad( tiledImage, tile, time, image, errorMsg, tileRequest ) {\n if ( !image ) {\n $.console.log( \"Tile %s failed to load: %s - error: %s\", tile, tile.url, errorMsg );\n /**\n * Triggered when a tile fails to load.\n *\n * @event tile-load-failed\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Tile} tile - The tile that failed to load.\n * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image the tile belongs to.\n * @property {number} time - The time in milliseconds when the tile load began.\n * @property {string} message - The error message.\n * @property {XMLHttpRequest} tileRequest - The XMLHttpRequest used to load the tile if available.\n */\n tiledImage.viewer.raiseEvent(\"tile-load-failed\", {\n tile: tile,\n tiledImage: tiledImage,\n time: time,\n message: errorMsg,\n tileRequest: tileRequest\n });\n tile.loading = false;\n tile.exists = false;\n return;\n }\n\n if ( time < tiledImage.lastResetTime ) {\n $.console.log( \"Ignoring tile %s loaded before reset: %s\", tile, tile.url );\n tile.loading = false;\n return;\n }\n\n var finish = function() {\n var cutoff = tiledImage.source.getClosestLevel();\n setTileLoaded(tiledImage, tile, image, cutoff, tileRequest);\n };\n\n // Check if we're mid-update; this can happen on IE8 because image load events for\n // cached images happen immediately there\n if ( !tiledImage._midDraw ) {\n finish();\n } else {\n // Wait until after the update, in case caching unloads any tiles\n window.setTimeout( finish, 1);\n }\n}\n\n/**\n * @private\n * @inner\n * @param {OpenSeadragon.TiledImage} tiledImage\n * @param {OpenSeadragon.Tile} tile\n * @param {Image} image\n * @param {Number} cutoff\n */\nfunction setTileLoaded(tiledImage, tile, image, cutoff, tileRequest) {\n var increment = 0;\n\n function getCompletionCallback() {\n increment++;\n return completionCallback;\n }\n\n function completionCallback() {\n increment--;\n if (increment === 0) {\n tile.loading = false;\n tile.loaded = true;\n if (!tile.context2D) {\n tiledImage._tileCache.cacheTile({\n image: image,\n tile: tile,\n cutoff: cutoff,\n tiledImage: tiledImage\n });\n }\n tiledImage._needsDraw = true;\n }\n }\n\n /**\n * Triggered when a tile has just been loaded in memory. That means that the\n * image has been downloaded and can be modified before being drawn to the canvas.\n *\n * @event tile-loaded\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {Image} image - The image of the tile.\n * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image of the loaded tile.\n * @property {OpenSeadragon.Tile} tile - The tile which has been loaded.\n * @property {XMLHttpRequest} tiledImage - The AJAX request that loaded this tile (if applicable).\n * @property {function} getCompletionCallback - A function giving a callback to call\n * when the asynchronous processing of the image is done. The image will be\n * marked as entirely loaded when the callback has been called once for each\n * call to getCompletionCallback.\n */\n tiledImage.viewer.raiseEvent(\"tile-loaded\", {\n tile: tile,\n tiledImage: tiledImage,\n tileRequest: tileRequest,\n image: image,\n getCompletionCallback: getCompletionCallback\n });\n // In case the completion callback is never called, we at least force it once.\n getCompletionCallback()();\n}\n\n/**\n * @private\n * @inner\n * @param {OpenSeadragon.Tile} tile\n * @param {Boolean} overlap\n * @param {OpenSeadragon.Viewport} viewport\n * @param {OpenSeadragon.Point} viewportCenter\n * @param {Number} levelVisibility\n * @param {OpenSeadragon.TiledImage} tiledImage\n */\nfunction positionTile( tile, overlap, viewport, viewportCenter, levelVisibility, tiledImage ){\n var boundsTL = tile.bounds.getTopLeft();\n\n boundsTL.x *= tiledImage._scaleSpring.current.value;\n boundsTL.y *= tiledImage._scaleSpring.current.value;\n boundsTL.x += tiledImage._xSpring.current.value;\n boundsTL.y += tiledImage._ySpring.current.value;\n\n var boundsSize = tile.bounds.getSize();\n\n boundsSize.x *= tiledImage._scaleSpring.current.value;\n boundsSize.y *= tiledImage._scaleSpring.current.value;\n\n var positionC = viewport.pixelFromPointNoRotate(boundsTL, true),\n positionT = viewport.pixelFromPointNoRotate(boundsTL, false),\n sizeC = viewport.deltaPixelsFromPointsNoRotate(boundsSize, true),\n sizeT = viewport.deltaPixelsFromPointsNoRotate(boundsSize, false),\n tileCenter = positionT.plus( sizeT.divide( 2 ) ),\n tileSquaredDistance = viewportCenter.squaredDistanceTo( tileCenter );\n\n if ( !overlap ) {\n sizeC = sizeC.plus( new $.Point( 1, 1 ) );\n }\n\n if (tile.isRightMost && tiledImage.wrapHorizontal) {\n sizeC.x += 0.75; // Otherwise Firefox and Safari show seams\n }\n\n if (tile.isBottomMost && tiledImage.wrapVertical) {\n sizeC.y += 0.75; // Otherwise Firefox and Safari show seams\n }\n\n tile.position = positionC;\n tile.size = sizeC;\n tile.squaredDistance = tileSquaredDistance;\n tile.visibility = levelVisibility;\n}\n\n/**\n * @private\n * @inner\n * Updates the opacity of a tile according to the time it has been on screen\n * to perform a fade-in.\n * Updates coverage once a tile is fully opaque.\n * Returns whether the fade-in has completed.\n *\n * @param {OpenSeadragon.TiledImage} tiledImage\n * @param {OpenSeadragon.Tile} tile\n * @param {Number} x\n * @param {Number} y\n * @param {Number} level\n * @param {Number} levelOpacity\n * @param {Number} currentTime\n * @returns {Boolean}\n */\nfunction blendTile( tiledImage, tile, x, y, level, levelOpacity, currentTime ){\n var blendTimeMillis = 1000 * tiledImage.blendTime,\n deltaTime,\n opacity;\n\n if ( !tile.blendStart ) {\n tile.blendStart = currentTime;\n }\n\n deltaTime = currentTime - tile.blendStart;\n opacity = blendTimeMillis ? Math.min( 1, deltaTime / ( blendTimeMillis ) ) : 1;\n\n if ( tiledImage.alwaysBlend ) {\n opacity *= levelOpacity;\n }\n\n tile.opacity = opacity;\n\n tiledImage.lastDrawn.push( tile );\n\n if ( opacity == 1 ) {\n setCoverage( tiledImage.coverage, level, x, y, true );\n tiledImage._hasOpaqueTile = true;\n } else if ( deltaTime < blendTimeMillis ) {\n return true;\n }\n\n return false;\n}\n\n/**\n * @private\n * @inner\n * Returns true if the given tile provides coverage to lower-level tiles of\n * lower resolution representing the same content. If neither x nor y is\n * given, returns true if the entire visible level provides coverage.\n *\n * Note that out-of-bounds tiles provide coverage in this sense, since\n * there's no content that they would need to cover. Tiles at non-existent\n * levels that are within the image bounds, however, do not.\n *\n * @param {Object} coverage - A '3d' dictionary [level][x][y] --> Boolean.\n * @param {Number} level - The resolution level of the tile.\n * @param {Number} x - The X position of the tile.\n * @param {Number} y - The Y position of the tile.\n * @returns {Boolean}\n */\nfunction providesCoverage( coverage, level, x, y ) {\n var rows,\n cols,\n i, j;\n\n if ( !coverage[ level ] ) {\n return false;\n }\n\n if ( x === undefined || y === undefined ) {\n rows = coverage[ level ];\n for ( i in rows ) {\n if ( rows.hasOwnProperty( i ) ) {\n cols = rows[ i ];\n for ( j in cols ) {\n if ( cols.hasOwnProperty( j ) && !cols[ j ] ) {\n return false;\n }\n }\n }\n }\n\n return true;\n }\n\n return (\n coverage[ level ][ x] === undefined ||\n coverage[ level ][ x ][ y ] === undefined ||\n coverage[ level ][ x ][ y ] === true\n );\n}\n\n/**\n * @private\n * @inner\n * Returns true if the given tile is completely covered by higher-level\n * tiles of higher resolution representing the same content. If neither x\n * nor y is given, returns true if the entire visible level is covered.\n *\n * @param {Object} coverage - A '3d' dictionary [level][x][y] --> Boolean.\n * @param {Number} level - The resolution level of the tile.\n * @param {Number} x - The X position of the tile.\n * @param {Number} y - The Y position of the tile.\n * @returns {Boolean}\n */\nfunction isCovered( coverage, level, x, y ) {\n if ( x === undefined || y === undefined ) {\n return providesCoverage( coverage, level + 1 );\n } else {\n return (\n providesCoverage( coverage, level + 1, 2 * x, 2 * y ) &&\n providesCoverage( coverage, level + 1, 2 * x, 2 * y + 1 ) &&\n providesCoverage( coverage, level + 1, 2 * x + 1, 2 * y ) &&\n providesCoverage( coverage, level + 1, 2 * x + 1, 2 * y + 1 )\n );\n }\n}\n\n/**\n * @private\n * @inner\n * Sets whether the given tile provides coverage or not.\n *\n * @param {Object} coverage - A '3d' dictionary [level][x][y] --> Boolean.\n * @param {Number} level - The resolution level of the tile.\n * @param {Number} x - The X position of the tile.\n * @param {Number} y - The Y position of the tile.\n * @param {Boolean} covers - Whether the tile provides coverage.\n */\nfunction setCoverage( coverage, level, x, y, covers ) {\n if ( !coverage[ level ] ) {\n $.console.warn(\n \"Setting coverage for a tile before its level's coverage has been reset: %s\",\n level\n );\n return;\n }\n\n if ( !coverage[ level ][ x ] ) {\n coverage[ level ][ x ] = {};\n }\n\n coverage[ level ][ x ][ y ] = covers;\n}\n\n/**\n * @private\n * @inner\n * Resets coverage information for the given level. This should be called\n * after every draw routine. Note that at the beginning of the next draw\n * routine, coverage for every visible tile should be explicitly set.\n *\n * @param {Object} coverage - A '3d' dictionary [level][x][y] --> Boolean.\n * @param {Number} level - The resolution level of tiles to completely reset.\n */\nfunction resetCoverage( coverage, level ) {\n coverage[ level ] = {};\n}\n\n/**\n * @private\n * @inner\n * Determines whether the 'last best' tile for the area is better than the\n * tile in question.\n *\n * @param {OpenSeadragon.Tile} previousBest\n * @param {OpenSeadragon.Tile} tile\n * @returns {OpenSeadragon.Tile} The new best tile.\n */\nfunction compareTiles( previousBest, tile ) {\n if ( !previousBest ) {\n return tile;\n }\n\n if ( tile.visibility > previousBest.visibility ) {\n return tile;\n } else if ( tile.visibility == previousBest.visibility ) {\n if ( tile.squaredDistance < previousBest.squaredDistance ) {\n return tile;\n }\n }\n\n return previousBest;\n}\n\n/**\n * @private\n * @inner\n * Draws a TiledImage.\n * @param {OpenSeadragon.TiledImage} tiledImage\n * @param {OpenSeadragon.Tile[]} lastDrawn - An unordered list of Tiles drawn last frame.\n */\nfunction drawTiles( tiledImage, lastDrawn ) {\n if (tiledImage.opacity === 0 || (lastDrawn.length === 0 && !tiledImage.placeholderFillStyle)) {\n return;\n }\n\n var tile = lastDrawn[0];\n var useSketch;\n\n if (tile) {\n useSketch = tiledImage.opacity < 1 ||\n (tiledImage.compositeOperation &&\n tiledImage.compositeOperation !== 'source-over') ||\n (!tiledImage._isBottomItem() && tile._hasTransparencyChannel());\n }\n\n var sketchScale;\n var sketchTranslate;\n\n var zoom = tiledImage.viewport.getZoom(true);\n var imageZoom = tiledImage.viewportToImageZoom(zoom);\n\n if (lastDrawn.length > 1 &&\n imageZoom > tiledImage.smoothTileEdgesMinZoom &&\n !tiledImage.iOSDevice &&\n tiledImage.getRotation(true) % 360 === 0 && // TODO: support tile edge smoothing with tiled image rotation.\n $.supportsCanvas) {\n // When zoomed in a lot (>100%) the tile edges are visible.\n // So we have to composite them at ~100% and scale them up together.\n // Note: Disabled on iOS devices per default as it causes a native crash\n useSketch = true;\n sketchScale = tile.getScaleForEdgeSmoothing();\n sketchTranslate = tile.getTranslationForEdgeSmoothing(sketchScale,\n tiledImage._drawer.getCanvasSize(false),\n tiledImage._drawer.getCanvasSize(true));\n }\n\n var bounds;\n if (useSketch) {\n if (!sketchScale) {\n // Except when edge smoothing, we only clean the part of the\n // sketch canvas we are going to use for performance reasons.\n bounds = tiledImage.viewport.viewportToViewerElementRectangle(\n tiledImage.getClippedBounds(true))\n .getIntegerBoundingBox()\n .times($.pixelDensityRatio);\n }\n tiledImage._drawer._clear(true, bounds);\n }\n\n // When scaling, we must rotate only when blending the sketch canvas to\n // avoid interpolation\n if (!sketchScale) {\n if (tiledImage.viewport.degrees !== 0) {\n tiledImage._drawer._offsetForRotation({\n degrees: tiledImage.viewport.degrees,\n useSketch: useSketch\n });\n }\n if (tiledImage.getRotation(true) % 360 !== 0) {\n tiledImage._drawer._offsetForRotation({\n degrees: tiledImage.getRotation(true),\n point: tiledImage.viewport.pixelFromPointNoRotate(\n tiledImage._getRotationPoint(true), true),\n useSketch: useSketch\n });\n }\n }\n\n var usedClip = false;\n if ( tiledImage._clip ) {\n tiledImage._drawer.saveContext(useSketch);\n\n var box = tiledImage.imageToViewportRectangle(tiledImage._clip, true);\n box = box.rotate(-tiledImage.getRotation(true), tiledImage._getRotationPoint(true));\n var clipRect = tiledImage._drawer.viewportToDrawerRectangle(box);\n if (sketchScale) {\n clipRect = clipRect.times(sketchScale);\n }\n if (sketchTranslate) {\n clipRect = clipRect.translate(sketchTranslate);\n }\n tiledImage._drawer.setClip(clipRect, useSketch);\n\n usedClip = true;\n }\n\n if ( tiledImage.placeholderFillStyle && tiledImage._hasOpaqueTile === false ) {\n var placeholderRect = tiledImage._drawer.viewportToDrawerRectangle(tiledImage.getBounds(true));\n if (sketchScale) {\n placeholderRect = placeholderRect.times(sketchScale);\n }\n if (sketchTranslate) {\n placeholderRect = placeholderRect.translate(sketchTranslate);\n }\n\n var fillStyle = null;\n if ( typeof tiledImage.placeholderFillStyle === \"function\" ) {\n fillStyle = tiledImage.placeholderFillStyle(tiledImage, tiledImage._drawer.context);\n }\n else {\n fillStyle = tiledImage.placeholderFillStyle;\n }\n\n tiledImage._drawer.drawRectangle(placeholderRect, fillStyle, useSketch);\n }\n\n for (var i = lastDrawn.length - 1; i >= 0; i--) {\n tile = lastDrawn[ i ];\n tiledImage._drawer.drawTile( tile, tiledImage._drawingHandler, useSketch, sketchScale, sketchTranslate );\n tile.beingDrawn = true;\n\n if( tiledImage.viewer ){\n /**\n * - Needs documentation -\n *\n * @event tile-drawn\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.\n * @property {OpenSeadragon.Tile} tile\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n tiledImage.viewer.raiseEvent( 'tile-drawn', {\n tiledImage: tiledImage,\n tile: tile\n });\n }\n }\n\n if ( usedClip ) {\n tiledImage._drawer.restoreContext( useSketch );\n }\n\n if (!sketchScale) {\n if (tiledImage.getRotation(true) % 360 !== 0) {\n tiledImage._drawer._restoreRotationChanges(useSketch);\n }\n if (tiledImage.viewport.degrees !== 0) {\n tiledImage._drawer._restoreRotationChanges(useSketch);\n }\n }\n\n if (useSketch) {\n if (sketchScale) {\n if (tiledImage.viewport.degrees !== 0) {\n tiledImage._drawer._offsetForRotation({\n degrees: tiledImage.viewport.degrees,\n useSketch: false\n });\n }\n if (tiledImage.getRotation(true) % 360 !== 0) {\n tiledImage._drawer._offsetForRotation({\n degrees: tiledImage.getRotation(true),\n point: tiledImage.viewport.pixelFromPointNoRotate(\n tiledImage._getRotationPoint(true), true),\n useSketch: false\n });\n }\n }\n tiledImage._drawer.blendSketch({\n opacity: tiledImage.opacity,\n scale: sketchScale,\n translate: sketchTranslate,\n compositeOperation: tiledImage.compositeOperation,\n bounds: bounds\n });\n if (sketchScale) {\n if (tiledImage.getRotation(true) % 360 !== 0) {\n tiledImage._drawer._restoreRotationChanges(false);\n }\n if (tiledImage.viewport.degrees !== 0) {\n tiledImage._drawer._restoreRotationChanges(false);\n }\n }\n }\n drawDebugInfo( tiledImage, lastDrawn );\n}\n\n/**\n * @private\n * @inner\n * Draws special debug information for a TiledImage if in debug mode.\n * @param {OpenSeadragon.TiledImage} tiledImage\n * @param {OpenSeadragon.Tile[]} lastDrawn - An unordered list of Tiles drawn last frame.\n */\nfunction drawDebugInfo( tiledImage, lastDrawn ) {\n if( tiledImage.debugMode ) {\n for ( var i = lastDrawn.length - 1; i >= 0; i-- ) {\n var tile = lastDrawn[ i ];\n try {\n tiledImage._drawer.drawDebugInfo(\n tile, lastDrawn.length, i, tiledImage);\n } catch(e) {\n $.console.error(e);\n }\n }\n }\n}\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - TileCache\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n// private class\nvar TileRecord = function( options ) {\n $.console.assert( options, \"[TileCache.cacheTile] options is required\" );\n $.console.assert( options.tile, \"[TileCache.cacheTile] options.tile is required\" );\n $.console.assert( options.tiledImage, \"[TileCache.cacheTile] options.tiledImage is required\" );\n this.tile = options.tile;\n this.tiledImage = options.tiledImage;\n};\n\n// private class\nvar ImageRecord = function(options) {\n $.console.assert( options, \"[ImageRecord] options is required\" );\n $.console.assert( options.image, \"[ImageRecord] options.image is required\" );\n this._image = options.image;\n this._tiles = [];\n};\n\nImageRecord.prototype = {\n destroy: function() {\n this._image = null;\n this._renderedContext = null;\n this._tiles = null;\n },\n\n getImage: function() {\n return this._image;\n },\n\n getRenderedContext: function() {\n if (!this._renderedContext) {\n var canvas = document.createElement( 'canvas' );\n canvas.width = this._image.width;\n canvas.height = this._image.height;\n this._renderedContext = canvas.getContext('2d');\n this._renderedContext.drawImage( this._image, 0, 0 );\n //since we are caching the prerendered image on a canvas\n //allow the image to not be held in memory\n this._image = null;\n }\n return this._renderedContext;\n },\n\n setRenderedContext: function(renderedContext) {\n $.console.error(\"ImageRecord.setRenderedContext is deprecated. \" +\n \"The rendered context should be created by the ImageRecord \" +\n \"itself when calling ImageRecord.getRenderedContext.\");\n this._renderedContext = renderedContext;\n },\n\n addTile: function(tile) {\n $.console.assert(tile, '[ImageRecord.addTile] tile is required');\n this._tiles.push(tile);\n },\n\n removeTile: function(tile) {\n for (var i = 0; i < this._tiles.length; i++) {\n if (this._tiles[i] === tile) {\n this._tiles.splice(i, 1);\n return;\n }\n }\n\n $.console.warn('[ImageRecord.removeTile] trying to remove unknown tile', tile);\n },\n\n getTileCount: function() {\n return this._tiles.length;\n }\n};\n\n/**\n * @class TileCache\n * @memberof OpenSeadragon\n * @classdesc Stores all the tiles displayed in a {@link OpenSeadragon.Viewer}.\n * You generally won't have to interact with the TileCache directly.\n * @param {Object} options - Configuration for this TileCache.\n * @param {Number} [options.maxImageCacheCount] - See maxImageCacheCount in\n * {@link OpenSeadragon.Options} for details.\n */\n$.TileCache = function( options ) {\n options = options || {};\n\n this._maxImageCacheCount = options.maxImageCacheCount || $.DEFAULT_SETTINGS.maxImageCacheCount;\n this._tilesLoaded = [];\n this._imagesLoaded = [];\n this._imagesLoadedCount = 0;\n};\n\n/** @lends OpenSeadragon.TileCache.prototype */\n$.TileCache.prototype = {\n /**\n * @returns {Number} The total number of tiles that have been loaded by\n * this TileCache.\n */\n numTilesLoaded: function() {\n return this._tilesLoaded.length;\n },\n\n /**\n * Caches the specified tile, removing an old tile if necessary to stay under the\n * maxImageCacheCount specified on construction. Note that if multiple tiles reference\n * the same image, there may be more tiles than maxImageCacheCount; the goal is to keep\n * the number of images below that number. Note, as well, that even the number of images\n * may temporarily surpass that number, but should eventually come back down to the max specified.\n * @param {Object} options - Tile info.\n * @param {OpenSeadragon.Tile} options.tile - The tile to cache.\n * @param {String} options.tile.cacheKey - The unique key used to identify this tile in the cache.\n * @param {Image} options.image - The image of the tile to cache.\n * @param {OpenSeadragon.TiledImage} options.tiledImage - The TiledImage that owns that tile.\n * @param {Number} [options.cutoff=0] - If adding this tile goes over the cache max count, this\n * function will release an old tile. The cutoff option specifies a tile level at or below which\n * tiles will not be released.\n */\n cacheTile: function( options ) {\n $.console.assert( options, \"[TileCache.cacheTile] options is required\" );\n $.console.assert( options.tile, \"[TileCache.cacheTile] options.tile is required\" );\n $.console.assert( options.tile.cacheKey, \"[TileCache.cacheTile] options.tile.cacheKey is required\" );\n $.console.assert( options.tiledImage, \"[TileCache.cacheTile] options.tiledImage is required\" );\n\n var cutoff = options.cutoff || 0;\n var insertionIndex = this._tilesLoaded.length;\n\n var imageRecord = this._imagesLoaded[options.tile.cacheKey];\n if (!imageRecord) {\n $.console.assert( options.image, \"[TileCache.cacheTile] options.image is required to create an ImageRecord\" );\n imageRecord = this._imagesLoaded[options.tile.cacheKey] = new ImageRecord({\n image: options.image\n });\n\n this._imagesLoadedCount++;\n }\n\n imageRecord.addTile(options.tile);\n options.tile.cacheImageRecord = imageRecord;\n\n // Note that just because we're unloading a tile doesn't necessarily mean\n // we're unloading an image. With repeated calls it should sort itself out, though.\n if ( this._imagesLoadedCount > this._maxImageCacheCount ) {\n var worstTile = null;\n var worstTileIndex = -1;\n var worstTileRecord = null;\n var prevTile, worstTime, worstLevel, prevTime, prevLevel, prevTileRecord;\n\n for ( var i = this._tilesLoaded.length - 1; i >= 0; i-- ) {\n prevTileRecord = this._tilesLoaded[ i ];\n prevTile = prevTileRecord.tile;\n\n if ( prevTile.level <= cutoff || prevTile.beingDrawn ) {\n continue;\n } else if ( !worstTile ) {\n worstTile = prevTile;\n worstTileIndex = i;\n worstTileRecord = prevTileRecord;\n continue;\n }\n\n prevTime = prevTile.lastTouchTime;\n worstTime = worstTile.lastTouchTime;\n prevLevel = prevTile.level;\n worstLevel = worstTile.level;\n\n if ( prevTime < worstTime ||\n ( prevTime == worstTime && prevLevel > worstLevel ) ) {\n worstTile = prevTile;\n worstTileIndex = i;\n worstTileRecord = prevTileRecord;\n }\n }\n\n if ( worstTile && worstTileIndex >= 0 ) {\n this._unloadTile(worstTileRecord);\n insertionIndex = worstTileIndex;\n }\n }\n\n this._tilesLoaded[ insertionIndex ] = new TileRecord({\n tile: options.tile,\n tiledImage: options.tiledImage\n });\n },\n\n /**\n * Clears all tiles associated with the specified tiledImage.\n * @param {OpenSeadragon.TiledImage} tiledImage\n */\n clearTilesFor: function( tiledImage ) {\n $.console.assert(tiledImage, '[TileCache.clearTilesFor] tiledImage is required');\n var tileRecord;\n for ( var i = 0; i < this._tilesLoaded.length; ++i ) {\n tileRecord = this._tilesLoaded[ i ];\n if ( tileRecord.tiledImage === tiledImage ) {\n this._unloadTile(tileRecord);\n this._tilesLoaded.splice( i, 1 );\n i--;\n }\n }\n },\n\n // private\n getImageRecord: function(cacheKey) {\n $.console.assert(cacheKey, '[TileCache.getImageRecord] cacheKey is required');\n return this._imagesLoaded[cacheKey];\n },\n\n // private\n _unloadTile: function(tileRecord) {\n $.console.assert(tileRecord, '[TileCache._unloadTile] tileRecord is required');\n var tile = tileRecord.tile;\n var tiledImage = tileRecord.tiledImage;\n\n tile.unload();\n tile.cacheImageRecord = null;\n\n var imageRecord = this._imagesLoaded[tile.cacheKey];\n imageRecord.removeTile(tile);\n if (!imageRecord.getTileCount()) {\n imageRecord.destroy();\n delete this._imagesLoaded[tile.cacheKey];\n this._imagesLoadedCount--;\n }\n\n /**\n * Triggered when a tile has just been unloaded from memory.\n *\n * @event tile-unloaded\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image of the unloaded tile.\n * @property {OpenSeadragon.Tile} tile - The tile which has been unloaded.\n */\n tiledImage.viewer.raiseEvent(\"tile-unloaded\", {\n tile: tile,\n tiledImage: tiledImage\n });\n }\n};\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - World\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class World\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.EventSource\n * @classdesc Keeps track of all of the tiled images in the scene.\n * @param {Object} options - World options.\n * @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this World.\n **/\n$.World = function( options ) {\n var _this = this;\n\n $.console.assert( options.viewer, \"[World] options.viewer is required\" );\n\n $.EventSource.call( this );\n\n this.viewer = options.viewer;\n this._items = [];\n this._needsDraw = false;\n this._autoRefigureSizes = true;\n this._needsSizesFigured = false;\n this._delegatedFigureSizes = function(event) {\n if (_this._autoRefigureSizes) {\n _this._figureSizes();\n } else {\n _this._needsSizesFigured = true;\n }\n };\n\n this._figureSizes();\n};\n\n$.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.World.prototype */{\n /**\n * Add the specified item.\n * @param {OpenSeadragon.TiledImage} item - The item to add.\n * @param {Number} [options.index] - Index for the item. If not specified, goes at the top.\n * @fires OpenSeadragon.World.event:add-item\n * @fires OpenSeadragon.World.event:metrics-change\n */\n addItem: function( item, options ) {\n $.console.assert(item, \"[World.addItem] item is required\");\n $.console.assert(item instanceof $.TiledImage, \"[World.addItem] only TiledImages supported at this time\");\n\n options = options || {};\n if (options.index !== undefined) {\n var index = Math.max(0, Math.min(this._items.length, options.index));\n this._items.splice(index, 0, item);\n } else {\n this._items.push( item );\n }\n\n if (this._autoRefigureSizes) {\n this._figureSizes();\n } else {\n this._needsSizesFigured = true;\n }\n\n this._needsDraw = true;\n\n item.addHandler('bounds-change', this._delegatedFigureSizes);\n item.addHandler('clip-change', this._delegatedFigureSizes);\n\n /**\n * Raised when an item is added to the World.\n * @event add-item\n * @memberOf OpenSeadragon.World\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the World which raised the event.\n * @property {OpenSeadragon.TiledImage} item - The item that has been added.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'add-item', {\n item: item\n } );\n },\n\n /**\n * Get the item at the specified index.\n * @param {Number} index - The item's index.\n * @returns {OpenSeadragon.TiledImage} The item at the specified index.\n */\n getItemAt: function( index ) {\n $.console.assert(index !== undefined, \"[World.getItemAt] index is required\");\n return this._items[ index ];\n },\n\n /**\n * Get the index of the given item or -1 if not present.\n * @param {OpenSeadragon.TiledImage} item - The item.\n * @returns {Number} The index of the item or -1 if not present.\n */\n getIndexOfItem: function( item ) {\n $.console.assert(item, \"[World.getIndexOfItem] item is required\");\n return $.indexOf( this._items, item );\n },\n\n /**\n * @returns {Number} The number of items used.\n */\n getItemCount: function() {\n return this._items.length;\n },\n\n /**\n * Change the index of a item so that it appears over or under others.\n * @param {OpenSeadragon.TiledImage} item - The item to move.\n * @param {Number} index - The new index.\n * @fires OpenSeadragon.World.event:item-index-change\n */\n setItemIndex: function( item, index ) {\n $.console.assert(item, \"[World.setItemIndex] item is required\");\n $.console.assert(index !== undefined, \"[World.setItemIndex] index is required\");\n\n var oldIndex = this.getIndexOfItem( item );\n\n if ( index >= this._items.length ) {\n throw new Error( \"Index bigger than number of layers.\" );\n }\n\n if ( index === oldIndex || oldIndex === -1 ) {\n return;\n }\n\n this._items.splice( oldIndex, 1 );\n this._items.splice( index, 0, item );\n this._needsDraw = true;\n\n /**\n * Raised when the order of the indexes has been changed.\n * @event item-index-change\n * @memberOf OpenSeadragon.World\n * @type {object}\n * @property {OpenSeadragon.World} eventSource - A reference to the World which raised the event.\n * @property {OpenSeadragon.TiledImage} item - The item whose index has\n * been changed\n * @property {Number} previousIndex - The previous index of the item\n * @property {Number} newIndex - The new index of the item\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'item-index-change', {\n item: item,\n previousIndex: oldIndex,\n newIndex: index\n } );\n },\n\n /**\n * Remove an item.\n * @param {OpenSeadragon.TiledImage} item - The item to remove.\n * @fires OpenSeadragon.World.event:remove-item\n * @fires OpenSeadragon.World.event:metrics-change\n */\n removeItem: function( item ) {\n $.console.assert(item, \"[World.removeItem] item is required\");\n\n var index = $.indexOf(this._items, item );\n if ( index === -1 ) {\n return;\n }\n\n item.removeHandler('bounds-change', this._delegatedFigureSizes);\n item.removeHandler('clip-change', this._delegatedFigureSizes);\n item.destroy();\n this._items.splice( index, 1 );\n this._figureSizes();\n this._needsDraw = true;\n this._raiseRemoveItem(item);\n },\n\n /**\n * Remove all items.\n * @fires OpenSeadragon.World.event:remove-item\n * @fires OpenSeadragon.World.event:metrics-change\n */\n removeAll: function() {\n // We need to make sure any pending images are canceled so the world items don't get messed up\n this.viewer._cancelPendingImages();\n var item;\n var i;\n for (i = 0; i < this._items.length; i++) {\n item = this._items[i];\n item.removeHandler('bounds-change', this._delegatedFigureSizes);\n item.removeHandler('clip-change', this._delegatedFigureSizes);\n item.destroy();\n }\n\n var removedItems = this._items;\n this._items = [];\n this._figureSizes();\n this._needsDraw = true;\n\n for (i = 0; i < removedItems.length; i++) {\n item = removedItems[i];\n this._raiseRemoveItem(item);\n }\n },\n\n /**\n * Clears all tiles and triggers updates for all items.\n */\n resetItems: function() {\n for ( var i = 0; i < this._items.length; i++ ) {\n this._items[i].reset();\n }\n },\n\n /**\n * Updates (i.e. animates bounds of) all items.\n */\n update: function() {\n var animated = false;\n for ( var i = 0; i < this._items.length; i++ ) {\n animated = this._items[i].update() || animated;\n }\n\n return animated;\n },\n\n /**\n * Draws all items.\n */\n draw: function() {\n for ( var i = 0; i < this._items.length; i++ ) {\n this._items[i].draw();\n }\n\n this._needsDraw = false;\n },\n\n /**\n * @returns {Boolean} true if any items need updating.\n */\n needsDraw: function() {\n for ( var i = 0; i < this._items.length; i++ ) {\n if ( this._items[i].needsDraw() ) {\n return true;\n }\n }\n return this._needsDraw;\n },\n\n /**\n * @returns {OpenSeadragon.Rect} The smallest rectangle that encloses all items, in viewport coordinates.\n */\n getHomeBounds: function() {\n return this._homeBounds.clone();\n },\n\n /**\n * To facilitate zoom constraints, we keep track of the pixel density of the\n * densest item in the World (i.e. the item whose content size to viewport size\n * ratio is the highest) and save it as this \"content factor\".\n * @returns {Number} the number of content units per viewport unit.\n */\n getContentFactor: function() {\n return this._contentFactor;\n },\n\n /**\n * As a performance optimization, setting this flag to false allows the bounds-change event handler\n * on tiledImages to skip calculations on the world bounds. If a lot of images are going to be positioned in\n * rapid succession, this is a good idea. When finished, setAutoRefigureSizes should be called with true\n * or the system may behave oddly.\n * @param {Boolean} [value] The value to which to set the flag.\n */\n setAutoRefigureSizes: function(value) {\n this._autoRefigureSizes = value;\n if (value & this._needsSizesFigured) {\n this._figureSizes();\n this._needsSizesFigured = false;\n }\n },\n\n /**\n * Arranges all of the TiledImages with the specified settings.\n * @param {Object} options - Specifies how to arrange.\n * @param {Boolean} [options.immediately=false] - Whether to animate to the new arrangement.\n * @param {String} [options.layout] - See collectionLayout in {@link OpenSeadragon.Options}.\n * @param {Number} [options.rows] - See collectionRows in {@link OpenSeadragon.Options}.\n * @param {Number} [options.columns] - See collectionColumns in {@link OpenSeadragon.Options}.\n * @param {Number} [options.tileSize] - See collectionTileSize in {@link OpenSeadragon.Options}.\n * @param {Number} [options.tileMargin] - See collectionTileMargin in {@link OpenSeadragon.Options}.\n * @fires OpenSeadragon.World.event:metrics-change\n */\n arrange: function(options) {\n options = options || {};\n var immediately = options.immediately || false;\n var layout = options.layout || $.DEFAULT_SETTINGS.collectionLayout;\n var rows = options.rows || $.DEFAULT_SETTINGS.collectionRows;\n var columns = options.columns || $.DEFAULT_SETTINGS.collectionColumns;\n var tileSize = options.tileSize || $.DEFAULT_SETTINGS.collectionTileSize;\n var tileMargin = options.tileMargin || $.DEFAULT_SETTINGS.collectionTileMargin;\n var increment = tileSize + tileMargin;\n var wrap;\n if (!options.rows && columns) {\n wrap = columns;\n } else {\n wrap = Math.ceil(this._items.length / rows);\n }\n var x = 0;\n var y = 0;\n var item, box, width, height, position;\n\n this.setAutoRefigureSizes(false);\n for (var i = 0; i < this._items.length; i++) {\n if (i && (i % wrap) === 0) {\n if (layout === 'horizontal') {\n y += increment;\n x = 0;\n } else {\n x += increment;\n y = 0;\n }\n }\n\n item = this._items[i];\n box = item.getBounds();\n if (box.width > box.height) {\n width = tileSize;\n } else {\n width = tileSize * (box.width / box.height);\n }\n\n height = width * (box.height / box.width);\n position = new $.Point(x + ((tileSize - width) / 2),\n y + ((tileSize - height) / 2));\n\n item.setPosition(position, immediately);\n item.setWidth(width, immediately);\n\n if (layout === 'horizontal') {\n x += increment;\n } else {\n y += increment;\n }\n }\n this.setAutoRefigureSizes(true);\n },\n\n // private\n _figureSizes: function() {\n var oldHomeBounds = this._homeBounds ? this._homeBounds.clone() : null;\n var oldContentSize = this._contentSize ? this._contentSize.clone() : null;\n var oldContentFactor = this._contentFactor || 0;\n\n if (!this._items.length) {\n this._homeBounds = new $.Rect(0, 0, 1, 1);\n this._contentSize = new $.Point(1, 1);\n this._contentFactor = 1;\n } else {\n var item = this._items[0];\n var bounds = item.getBounds();\n this._contentFactor = item.getContentSize().x / bounds.width;\n var clippedBounds = item.getClippedBounds().getBoundingBox();\n var left = clippedBounds.x;\n var top = clippedBounds.y;\n var right = clippedBounds.x + clippedBounds.width;\n var bottom = clippedBounds.y + clippedBounds.height;\n for (var i = 1; i < this._items.length; i++) {\n item = this._items[i];\n bounds = item.getBounds();\n this._contentFactor = Math.max(this._contentFactor,\n item.getContentSize().x / bounds.width);\n clippedBounds = item.getClippedBounds().getBoundingBox();\n left = Math.min(left, clippedBounds.x);\n top = Math.min(top, clippedBounds.y);\n right = Math.max(right, clippedBounds.x + clippedBounds.width);\n bottom = Math.max(bottom, clippedBounds.y + clippedBounds.height);\n }\n\n this._homeBounds = new $.Rect(left, top, right - left, bottom - top);\n this._contentSize = new $.Point(\n this._homeBounds.width * this._contentFactor,\n this._homeBounds.height * this._contentFactor);\n }\n\n if (this._contentFactor !== oldContentFactor ||\n !this._homeBounds.equals(oldHomeBounds) ||\n !this._contentSize.equals(oldContentSize)) {\n /**\n * Raised when the home bounds or content factor change.\n * @event metrics-change\n * @memberOf OpenSeadragon.World\n * @type {object}\n * @property {OpenSeadragon.World} eventSource - A reference to the World which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent('metrics-change', {});\n }\n },\n\n // private\n _raiseRemoveItem: function(item) {\n /**\n * Raised when an item is removed.\n * @event remove-item\n * @memberOf OpenSeadragon.World\n * @type {object}\n * @property {OpenSeadragon.World} eventSource - A reference to the World which raised the event.\n * @property {OpenSeadragon.TiledImage} item - The item's underlying item.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'remove-item', { item: item } );\n }\n});\n\n}( OpenSeadragon ));\n"]} \ No newline at end of file diff --git a/js/openseadragon/openseadragon-bin-2.3.1/openseadragon.min.js b/js/openseadragon/openseadragon-bin-2.3.1/openseadragon.min.js new file mode 100644 index 000000000..07e8bd921 --- /dev/null +++ b/js/openseadragon/openseadragon-bin-2.3.1/openseadragon.min.js @@ -0,0 +1,15 @@ +//! openseadragon 2.3.1 +//! Built on 2017-09-19 +//! Git commit: v2.3.1-0-08414cd +//! http://openseadragon.github.io +//! License: http://openseadragon.github.io/license/ + + +function OpenSeadragon(a){return new OpenSeadragon.Viewer(a)}!function(a){a.version={versionStr:"2.3.1",major:parseInt("2",10),minor:parseInt("3",10),revision:parseInt("1",10)};var b={"[object Boolean]":"boolean","[object Number]":"number","[object String]":"string","[object Function]":"function","[object Array]":"array","[object Date]":"date","[object RegExp]":"regexp","[object Object]":"object"},c=Object.prototype.toString,d=Object.prototype.hasOwnProperty;a.isFunction=function(b){return"function"===a.type(b)};a.isArray=Array.isArray||function(b){return"array"===a.type(b)};a.isWindow=function(a){return a&&"object"==typeof a&&"setInterval"in a};a.type=function(a){return null===a||void 0===a?String(a):b[c.call(a)]||"object"};a.isPlainObject=function(b){if(!b||"object"!==OpenSeadragon.type(b)||b.nodeType||a.isWindow(b))return!1;if(b.constructor&&!d.call(b,"constructor")&&!d.call(b.constructor.prototype,"isPrototypeOf"))return!1;var c;for(var e in b)c=e;return void 0===c||d.call(b,c)};a.isEmptyObject=function(a){for(var b in a)return!1;return!0};a.freezeObject=function(b){Object.freeze?a.freezeObject=Object.freeze:a.freezeObject=function(a){return a};return a.freezeObject(b)};a.supportsCanvas=function(){var b=document.createElement("canvas");return!(!a.isFunction(b.getContext)||!b.getContext("2d"))}();a.isCanvasTainted=function(a){var b=!1;try{a.getContext("2d").getImageData(0,0,1,1)}catch(a){b=!0}return b};a.pixelDensityRatio=function(){if(a.supportsCanvas){var b=document.createElement("canvas").getContext("2d");var c=window.devicePixelRatio||1;var d=b.webkitBackingStorePixelRatio||b.mozBackingStorePixelRatio||b.msBackingStorePixelRatio||b.oBackingStorePixelRatio||b.backingStorePixelRatio||1;return Math.max(c,1)/d}return 1}()}(OpenSeadragon);!function($){function getOffsetParent(a,b){return b&&a!=document.body?document.body:a.offsetParent}$.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=arguments.length,i=!1,j=1;if("boolean"==typeof g){i=g;g=arguments[1]||{};j=2}"object"==typeof g||OpenSeadragon.isFunction(g)||(g={});if(h===j){g=this;--j}for(;j=c.x&&b.x=c.y},getEvent:function(a){a?$.getEvent=function(a){return a}:$.getEvent=function(){return window.event};return $.getEvent(a)},getMousePosition:function(a){if("number"==typeof a.pageX)$.getMousePosition=function(a){var b=new $.Point;a=$.getEvent(a);b.x=a.pageX;b.y=a.pageY;return b};else{if("number"!=typeof a.clientX)throw new Error("Unknown event mouse position, no known technique.");$.getMousePosition=function(a){var b=new $.Point;a=$.getEvent(a);b.x=a.clientX+document.body.scrollLeft+document.documentElement.scrollLeft;b.y=a.clientY+document.body.scrollTop+document.documentElement.scrollTop;return b}}return $.getMousePosition(a)},getPageScroll:function(){var a=document.documentElement||{},b=document.body||{};if("number"==typeof window.pageXOffset)$.getPageScroll=function(){return new $.Point(window.pageXOffset,window.pageYOffset)};else if(b.scrollLeft||b.scrollTop)$.getPageScroll=function(){return new $.Point(document.body.scrollLeft,document.body.scrollTop)};else{if(!a.scrollLeft&&!a.scrollTop)return new $.Point(0,0);$.getPageScroll=function(){return new $.Point(document.documentElement.scrollLeft,document.documentElement.scrollTop)}}return $.getPageScroll()},setPageScroll:function(a){if("undefined"!=typeof window.scrollTo)$.setPageScroll=function(a){window.scrollTo(a.x,a.y)};else{var b=$.getPageScroll();if(b.x===a.x&&b.y===a.y)return;document.body.scrollLeft=a.x;document.body.scrollTop=a.y;var c=$.getPageScroll();if(c.x!==b.x&&c.y!==b.y){$.setPageScroll=function(a){document.body.scrollLeft=a.x;document.body.scrollTop=a.y};return}document.documentElement.scrollLeft=a.x;document.documentElement.scrollTop=a.y;c=$.getPageScroll();if(c.x!==b.x&&c.y!==b.y){$.setPageScroll=function(a){document.documentElement.scrollLeft=a.x;document.documentElement.scrollTop=a.y};return}$.setPageScroll=function(a){}}return $.setPageScroll(a)},getWindowSize:function(){var a=document.documentElement||{},b=document.body||{};if("number"==typeof window.innerWidth)$.getWindowSize=function(){return new $.Point(window.innerWidth,window.innerHeight)};else if(a.clientWidth||a.clientHeight)$.getWindowSize=function(){return new $.Point(document.documentElement.clientWidth,document.documentElement.clientHeight)};else{if(!b.clientWidth&&!b.clientHeight)throw new Error("Unknown window size, no known technique.");$.getWindowSize=function(){return new $.Point(document.body.clientWidth,document.body.clientHeight)}}return $.getWindowSize()},makeCenteredNode:function(a){a=$.getElement(a);var b=[$.makeNeutralElement("div"),$.makeNeutralElement("div"),$.makeNeutralElement("div")];$.extend(b[0].style,{display:"table",height:"100%",width:"100%"});$.extend(b[1].style,{display:"table-row"});$.extend(b[2].style,{display:"table-cell",verticalAlign:"middle",textAlign:"center"});b[0].appendChild(b[1]);b[1].appendChild(b[2]);b[2].appendChild(a);return b[0]},makeNeutralElement:function(a){var b=document.createElement(a),c=b.style;c.background="transparent none";c.border="none";c.margin="0px";c.padding="0px";c.position="static";return b},now:function(){Date.now?$.now=Date.now:$.now=function(){return(new Date).getTime()};return $.now()},makeTransparentImage:function(a){$.makeTransparentImage=function(a){var b=$.makeNeutralElement("img");b.src=a;return b};$.Browser.vendor==$.BROWSERS.IE&&$.Browser.version<7&&($.makeTransparentImage=function(a){var b=$.makeNeutralElement("img"),c=null;c=$.makeNeutralElement("span");c.style.display="inline-block";b.onload=function(){c.style.width=c.style.width||b.width+"px";c.style.height=c.style.height||b.height+"px";b.onload=null;b=null};b.src=a;c.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+a+"', sizingMethod='scale')";return c});return $.makeTransparentImage(a)},setElementOpacity:function(a,b,c){var d,e;a=$.getElement(a);c&&!$.Browser.alpha&&(b=Math.round(b));if($.Browser.opacity)a.style.opacity=b<1?b:"";else if(b<1){d=Math.round(100*b);e="alpha(opacity="+d+")";a.style.filter=e}else a.style.filter=""},setElementTouchActionNone:function(a){a=$.getElement(a);"undefined"!=typeof a.style.touchAction?a.style.touchAction="none":"undefined"!=typeof a.style.msTouchAction&&(a.style.msTouchAction="none")},addClass:function(a,b){a=$.getElement(a);a.className?(" "+a.className+" ").indexOf(" "+b+" ")===-1&&(a.className+=" "+b):a.className=b},indexOf:function(a,b,c){Array.prototype.indexOf?this.indexOf=function(a,b,c){return a.indexOf(b,c)}:this.indexOf=function(a,b,c){var d,e,f=c?c:0;if(!a)throw new TypeError;e=a.length;if(0===e||f>=e)return-1;f<0&&(f=e-Math.abs(f));for(d=f;d=200&&h.status<300||0===h.status&&"http:"!==g&&"https:"!==g)b(h);else{$.console.log("AJAX request returned %d: %s",h.status,a);$.isFunction(c)&&c(h)}}};try{h.open("GET",a,!0);f&&(h.responseType=f);if(e)for(var i in e)e.hasOwnProperty(i)&&e[i]&&h.setRequestHeader(i,e[i]);d&&(h.withCredentials=!0);h.send(null)}catch(d){var j=d.message;var k=$.Browser.vendor==$.BROWSERS.IE&&$.Browser.version<10;k&&"undefined"!=typeof d.number&&d.number==-2147024891&&(j+="\nSee http://msdn.microsoft.com/en-us/library/ms537505(v=vs.85).aspx#xdomain");$.console.log("%s while making AJAX request: %s",d.name,j);h.onreadystatechange=function(){};if(window.XDomainRequest){var l=new XDomainRequest;if(l){l.onload=function(a){$.isFunction(b)&&b({responseText:l.responseText,status:200,statusText:"OK"})};l.onerror=function(a){$.isFunction(c)&&c({responseText:l.responseText,status:444,statusText:"An error happened. Due to an XDomainRequest deficiency we can not extract any information about this error. Upgrade your browser."})};try{l.open("GET",a);l.send()}catch(a){$.isFunction(c)&&c(h,d)}}}else $.isFunction(c)&&c(h,d)}return h},jsonp:function(a){var b,c=a.url,d=document.head||document.getElementsByTagName("head")[0]||document.documentElement,e=a.callbackName||"openseadragon"+$.now(),f=window[e],g="$1"+e+"$2",h=a.param||"callback",i=a.callback;c=c.replace(/(\=)\?(&|$)|\?\?/i,g);c+=(/\?/.test(c)?"&":"?")+h+"="+e;window[e]=function(a){if(f)window[e]=f;else try{delete window[e]}catch(a){}i&&$.isFunction(i)&&i(a)};b=document.createElement("script");void 0===a.async&&!1===a.async||(b.async="async");a.scriptCharset&&(b.charset=a.scriptCharset);b.src=c;b.onload=b.onreadystatechange=function(a,c){if(c||!b.readyState||/loaded|complete/.test(b.readyState)){b.onload=b.onreadystatechange=null;d&&b.parentNode&&d.removeChild(b);b=void 0}};d.insertBefore(b,d.firstChild)},createFromDZI:function(){throw"OpenSeadragon.createFromDZI is deprecated, use Viewer.open."},parseXml:function(a){if(window.DOMParser)$.parseXml=function(a){var b,c=null;b=new DOMParser;c=b.parseFromString(a,"text/xml");return c};else{if(!window.ActiveXObject)throw new Error("Browser doesn't support XML DOM.");$.parseXml=function(a){var b=null;b=new ActiveXObject("Microsoft.XMLDOM");b.async=!1;b.loadXML(a);return b}}return $.parseXml(a)},parseJSON:function(string){window.JSON&&window.JSON.parse?$.parseJSON=window.JSON.parse:$.parseJSON=function(string){return eval("("+string+")")};return $.parseJSON(string)},imageFormatSupported:function(a){a=a?a:"";return!!FILEFORMATS[a.toLowerCase()]}});$.Browser={vendor:$.BROWSERS.UNKNOWN,version:0,alpha:!0};var FILEFORMATS={bmp:!1,jpeg:!0,jpg:!0,png:!0,tif:!1,wdp:!1},URLPARAMS={};!function(){var a,b=navigator.appVersion,c=navigator.userAgent;switch(navigator.appName){case"Microsoft Internet Explorer":if(window.attachEvent&&window.ActiveXObject){$.Browser.vendor=$.BROWSERS.IE;$.Browser.version=parseFloat(c.substring(c.indexOf("MSIE")+5,c.indexOf(";",c.indexOf("MSIE"))))}break;case"Netscape":if(window.addEventListener)if(c.indexOf("Firefox")>=0){$.Browser.vendor=$.BROWSERS.FIREFOX;$.Browser.version=parseFloat(c.substring(c.indexOf("Firefox")+8))}else if(c.indexOf("Safari")>=0){$.Browser.vendor=c.indexOf("Chrome")>=0?$.BROWSERS.CHROME:$.BROWSERS.SAFARI;$.Browser.version=parseFloat(c.substring(c.substring(0,c.indexOf("Safari")).lastIndexOf("/")+1,c.indexOf("Safari")))}else{a=new RegExp("Trident/.*rv:([0-9]{1,}[.0-9]{0,})");if(null!==a.exec(c)){$.Browser.vendor=$.BROWSERS.IE;$.Browser.version=parseFloat(RegExp.$1)}}break;case"Opera":$.Browser.vendor=$.BROWSERS.OPERA;$.Browser.version=parseFloat(b)}var d,e,f,g=window.location.search.substring(1),h=g.split("&");for(f=0;f0&&(URLPARAMS[d.substring(0,e)]=decodeURIComponent(d.substring(e+1)))}$.Browser.alpha=!($.Browser.vendor==$.BROWSERS.IE&&$.Browser.version<9||$.Browser.vendor==$.BROWSERS.CHROME&&$.Browser.version<2);$.Browser.opacity=!($.Browser.vendor==$.BROWSERS.IE&&$.Browser.version<9)}();var nullfunction=function(a){};$.console=window.console||{log:nullfunction,debug:nullfunction,info:nullfunction,warn:nullfunction,error:nullfunction,assert:nullfunction};!function(a){var b=a.requestAnimationFrame||a.mozRequestAnimationFrame||a.webkitRequestAnimationFrame||a.msRequestAnimationFrame;var c=a.cancelAnimationFrame||a.mozCancelAnimationFrame||a.webkitCancelAnimationFrame||a.msCancelAnimationFrame;if(b&&c){$.requestAnimationFrame=function(){return b.apply(a,arguments)};$.cancelAnimationFrame=function(){return c.apply(a,arguments)}}else{var d,e=[],f=[],g=0;$.requestAnimationFrame=function(a){e.push([++g,a]);d||(d=setInterval(function(){if(e.length){var a=$.now();var b=f;f=e;e=b;for(;f.length;)f.shift()[1](a)}else{clearInterval(d);d=void 0}},20));return g};$.cancelAnimationFrame=function(a){var b,c;for(b=0,c=e.length;b0){a.removeEvent(a.MouseTracker.captureElement,"mousemove",d.mousemovecaptured,!0);a.removeEvent(a.MouseTracker.captureElement,"mouseup",d.mouseupcaptured,!0);a.removeEvent(a.MouseTracker.captureElement,a.MouseTracker.unprefixedPointerEvents?"pointermove":"MSPointerMove",d.pointermovecaptured,!0);a.removeEvent(a.MouseTracker.captureElement,a.MouseTracker.unprefixedPointerEvents?"pointerup":"MSPointerUp",d.pointerupcaptured,!0);a.removeEvent(a.MouseTracker.captureElement,"touchmove",d.touchmovecaptured,!0);a.removeEvent(a.MouseTracker.captureElement,"touchend",d.touchendcaptured,!0);d.activePointersLists[c].captureCount=0}for(c=0;c0){for(d=0;d0){ja(a,b,f,0);c.captureCount=1;g(a,c.type);ha(a,b,f)}}}function M(b,c){var d,e,g,h,j=c.changedTouches.length,k=[],l=b.getActivePointersListByType("touch");d=a.now();if(l.getLength()>c.touches.length-j){a.console.warn("Tracked touch contact count doesn't match event.touches.length. Removing all tracked touch pointers.");L(b,c,l)}for(e=0;e8||"onwheel"in document.createElement("div")?"wheel":void 0!==document.onmousewheel?"mousewheel":"DOMMouseScroll";a.MouseTracker.supportsMouseCapture=function(){var b=document.createElement("div");return a.isFunction(b.setCapture)&&a.isFunction(b.releaseCapture)}();a.MouseTracker.subscribeEvents=["click","dblclick","keydown","keyup","keypress","focus","blur",a.MouseTracker.wheelEventName];"DOMMouseScroll"==a.MouseTracker.wheelEventName&&a.MouseTracker.subscribeEvents.push("MozMousePixelScroll");if(window.PointerEvent&&(window.navigator.pointerEnabled||a.Browser.vendor!==a.BROWSERS.IE)){a.MouseTracker.havePointerEvents=!0;a.MouseTracker.subscribeEvents.push("pointerover","pointerout","pointerdown","pointerup","pointermove","pointercancel");a.MouseTracker.unprefixedPointerEvents=!0;navigator.maxTouchPoints?a.MouseTracker.maxTouchPoints=navigator.maxTouchPoints:a.MouseTracker.maxTouchPoints=0;a.MouseTracker.haveMouseEnter=!1}else if(window.MSPointerEvent&&window.navigator.msPointerEnabled){a.MouseTracker.havePointerEvents=!0;a.MouseTracker.subscribeEvents.push("MSPointerOver","MSPointerOut","MSPointerDown","MSPointerUp","MSPointerMove","MSPointerCancel");a.MouseTracker.unprefixedPointerEvents=!1;navigator.msMaxTouchPoints?a.MouseTracker.maxTouchPoints=navigator.msMaxTouchPoints:a.MouseTracker.maxTouchPoints=0;a.MouseTracker.haveMouseEnter=!1}else{a.MouseTracker.havePointerEvents=!1;if(a.Browser.vendor===a.BROWSERS.IE&&a.Browser.version<9){a.MouseTracker.subscribeEvents.push("mouseenter","mouseleave");a.MouseTracker.haveMouseEnter=!0}else{a.MouseTracker.subscribeEvents.push("mouseover","mouseout");a.MouseTracker.haveMouseEnter=!1}a.MouseTracker.subscribeEvents.push("mousedown","mouseup","mousemove");"ontouchstart"in window&&a.MouseTracker.subscribeEvents.push("touchstart","touchend","touchmove","touchcancel");"ongesturestart"in window&&a.MouseTracker.subscribeEvents.push("gesturestart","gesturechange");a.MouseTracker.mousePointerId="legacy-mouse";a.MouseTracker.maxTouchPoints=10}a.MouseTracker.GesturePointList=function(a){this._gPoints=[];this.type=a;this.buttons=0;this.contacts=0;this.clicks=0;this.captureCount=0};a.MouseTracker.GesturePointList.prototype={getLength:function(){return this._gPoints.length},asArray:function(){return this._gPoints},add:function(a){return this._gPoints.push(a)},removeById:function(a){var b,c=this._gPoints.length;for(b=0;b1&&("mouse"===this.type||"pen"===this.type)&&(this.contacts=1)},removeContact:function(){--this.contacts;this.contacts<0&&(this.contacts=0)}};var qa=function(){try{return window.self!==window.top}catch(a){return!0}}()}(OpenSeadragon);!function(a){a.ControlAnchor={NONE:0,TOP_LEFT:1,TOP_RIGHT:2,BOTTOM_RIGHT:3,BOTTOM_LEFT:4,ABSOLUTE:5};a.Control=function(b,c,d){var e=b.parentNode;if("number"==typeof c){a.console.error("Passing an anchor directly into the OpenSeadragon.Control constructor is deprecated; please use an options object instead. Support for this deprecated variant is scheduled for removal in December 2013");c={anchor:c}}c.attachToViewer="undefined"==typeof c.attachToViewer||c.attachToViewer;this.autoFade="undefined"==typeof c.autoFade||c.autoFade;this.element=b;this.anchor=c.anchor;this.container=d;if(this.anchor==a.ControlAnchor.ABSOLUTE){this.wrapper=a.makeNeutralElement("div");this.wrapper.style.position="absolute";this.wrapper.style.top="number"==typeof c.top?c.top+"px":c.top;this.wrapper.style.left="number"==typeof c.left?c.left+"px":c.left;this.wrapper.style.height="number"==typeof c.height?c.height+"px":c.height;this.wrapper.style.width="number"==typeof c.width?c.width+"px":c.width;this.wrapper.style.margin="0px";this.wrapper.style.padding="0px";this.element.style.position="relative";this.element.style.top="0px";this.element.style.left="0px";this.element.style.height="100%";this.element.style.width="100%"}else{this.wrapper=a.makeNeutralElement("div");this.wrapper.style.display="inline-block";this.anchor==a.ControlAnchor.NONE&&(this.wrapper.style.width=this.wrapper.style.height="100%")}this.wrapper.appendChild(this.element);c.attachToViewer?this.anchor==a.ControlAnchor.TOP_RIGHT||this.anchor==a.ControlAnchor.BOTTOM_RIGHT?this.container.insertBefore(this.wrapper,this.container.firstChild):this.container.appendChild(this.wrapper):e.appendChild(this.wrapper)};a.Control.prototype={destroy:function(){this.wrapper.removeChild(this.element);this.container.removeChild(this.wrapper)},isVisible:function(){return"none"!=this.wrapper.style.display},setVisible:function(b){this.wrapper.style.display=b?this.anchor==a.ControlAnchor.ABSOLUTE?"block":"inline-block":"none"},setOpacity:function(b){this.element[a.SIGNAL]&&a.Browser.vendor==a.BROWSERS.IE?a.setElementOpacity(this.element,b,!0):a.setElementOpacity(this.wrapper,b,!0)}}}(OpenSeadragon);!function(a){function b(a,b){var c,d=a.controls;for(c=d.length-1;c>=0;c--)if(d[c].element==b)return c;return-1}a.ControlDock=function(b){var c,d,e=["topleft","topright","bottomright","bottomleft"];a.extend(!0,this,{id:"controldock-"+a.now()+"-"+Math.floor(1e6*Math.random()),container:a.makeNeutralElement("div"),controls:[]},b);this.container.onsubmit=function(){return!1};if(this.element){this.element=a.getElement(this.element);this.element.appendChild(this.container);this.element.style.position="relative";this.container.style.width="100%";this.container.style.height="100%"}for(d=0;d=0)){switch(d.anchor){case a.ControlAnchor.TOP_RIGHT:e=this.controls.topright;c.style.position="relative";c.style.paddingRight="0px";c.style.paddingTop="0px";break;case a.ControlAnchor.BOTTOM_RIGHT:e=this.controls.bottomright;c.style.position="relative";c.style.paddingRight="0px";c.style.paddingBottom="0px";break;case a.ControlAnchor.BOTTOM_LEFT:e=this.controls.bottomleft;c.style.position="relative";c.style.paddingLeft="0px";c.style.paddingBottom="0px";break;case a.ControlAnchor.TOP_LEFT:e=this.controls.topleft;c.style.position="relative";c.style.paddingLeft="0px";c.style.paddingTop="0px";break;case a.ControlAnchor.ABSOLUTE:e=this.container;c.style.margin="0px";c.style.padding="0px";break;default:case a.ControlAnchor.NONE:e=this.container;c.style.margin="0px";c.style.padding="0px"}this.controls.push(new a.Control(c,d,e));c.style.display="inline-block"}},removeControl:function(c){c=a.getElement(c);var d=b(this,c);if(d>=0){this.controls[d].destroy();this.controls.splice(d,1)}return this},clearControls:function(){for(;this.controls.length>0;)this.controls.pop().destroy();return this},areControlsEnabled:function(){var a;for(a=this.controls.length-1;a>=0;a--)if(this.controls[a].isVisible())return!0;return!1},setControlsEnabled:function(a){var b;for(b=this.controls.length-1;b>=0;b--)this.controls[b].setVisible(a);return this}}}(OpenSeadragon);!function(a){a.Placement=a.freezeObject({CENTER:0,TOP_LEFT:1,TOP:2,TOP_RIGHT:3,RIGHT:4,BOTTOM_RIGHT:5,BOTTOM:6,BOTTOM_LEFT:7,LEFT:8,properties:{0:{isLeft:!1,isHorizontallyCentered:!0,isRight:!1,isTop:!1,isVerticallyCentered:!0,isBottom:!1},1:{isLeft:!0,isHorizontallyCentered:!1,isRight:!1,isTop:!0,isVerticallyCentered:!1,isBottom:!1},2:{isLeft:!1,isHorizontallyCentered:!0,isRight:!1,isTop:!0,isVerticallyCentered:!1,isBottom:!1},3:{isLeft:!1,isHorizontallyCentered:!1,isRight:!0,isTop:!0,isVerticallyCentered:!1,isBottom:!1},4:{isLeft:!1,isHorizontallyCentered:!1,isRight:!0,isTop:!1,isVerticallyCentered:!0,isBottom:!1},5:{isLeft:!1,isHorizontallyCentered:!1,isRight:!0,isTop:!1,isVerticallyCentered:!1,isBottom:!0},6:{isLeft:!1,isHorizontallyCentered:!0,isRight:!1,isTop:!1,isVerticallyCentered:!1,isBottom:!0},7:{isLeft:!0,isHorizontallyCentered:!1,isRight:!1,isTop:!1,isVerticallyCentered:!1,isBottom:!0},8:{isLeft:!0,isHorizontallyCentered:!1,isRight:!1,isTop:!1,isVerticallyCentered:!0,isBottom:!1}}})}(OpenSeadragon);!function(a){function b(b){b=a.getElement(b);return new a.Point(0===b.clientWidth?1:b.clientWidth,0===b.clientHeight?1:b.clientHeight)}function c(b,c,d,e,f){function g(a,b){if(a.ready)e(a);else{a.addHandler("ready",function(){e(a)});a.addHandler("open-failed",function(a){f({message:a.message,source:b})})}}var h=b;if("string"==a.type(c))if(c.match(/^\s*<.*>\s*$/))c=a.parseXml(c);else if(c.match(/^\s*[\{\[].*[\}\]]\s*$/))try{var i=a.parseJSON(c);c=i}catch(a){}setTimeout(function(){if("string"==a.type(c)){c=new a.TileSource({url:c,crossOriginPolicy:void 0!==d.crossOriginPolicy?d.crossOriginPolicy:b.crossOriginPolicy,ajaxWithCredentials:b.ajaxWithCredentials,ajaxHeaders:b.ajaxHeaders,useCanvas:b.useCanvas,success:function(a){e(a.tileSource)}});c.addHandler("open-failed",function(a){f(a)})}else if(a.isPlainObject(c)||c.nodeType){void 0!==c.crossOriginPolicy||void 0===d.crossOriginPolicy&&void 0===b.crossOriginPolicy||(c.crossOriginPolicy=void 0!==d.crossOriginPolicy?d.crossOriginPolicy:b.crossOriginPolicy);void 0===c.ajaxWithCredentials&&(c.ajaxWithCredentials=b.ajaxWithCredentials);void 0===c.useCanvas&&(c.useCanvas=b.useCanvas);if(a.isFunction(c.getTileUrl)){var i=new a.TileSource(c);i.getTileUrl=c.getTileUrl;e(i)}else{var j=a.TileSource.determineType(h,c);if(!j){f({message:"Unable to load TileSource",source:c});return}var k=j.prototype.configure.apply(h,[c]);g(new j(k),c)}}else g(c,c)})}function d(b,c){if(c instanceof a.Overlay)return c;var d=null;if(c.element)d=a.getElement(c.element);else{var e=c.id?c.id:"openseadragon-overlay-"+Math.floor(1e7*Math.random());d=a.getElement(c.id);if(!d){d=document.createElement("a");d.href="#/overlay/"+e}d.id=e;a.addClass(d,c.className?c.className:"openseadragon-overlay")}var f=c.location;var g=c.width;var h=c.height;if(!f){var i=c.x;var j=c.y;if(void 0!==c.px){var k=b.viewport.imageToViewportRectangle(new a.Rect(c.px,c.py,g||0,h||0));i=k.x;j=k.y;g=void 0!==g?k.width:void 0;h=void 0!==h?k.height:void 0}f=new a.Point(i,j)}var l=c.placement;l&&"string"===a.type(l)&&(l=a.Placement[c.placement.toUpperCase()]);return new a.Overlay({element:d,location:f,placement:l,onDraw:c.onDraw,checkResize:c.checkResize,width:g,height:h,rotationMode:c.rotationMode})}function e(a,b){var c;for(c=a.length-1;c>=0;c--)if(a[c].element===b)return c;return-1}function f(b,c){return a.requestAnimationFrame(function(){c(b)})}function g(b){a.requestAnimationFrame(function(){i(b)})}function h(b){if(b.autoHideControls){b.controlsShouldFade=!0;b.controlsFadeBeginTime=a.now()+b.controlsFadeDelay;window.setTimeout(function(){g(b)},b.controlsFadeDelay)}}function i(b){var c,d,e,f;if(b.controlsShouldFade){c=a.now();d=c-b.controlsFadeBeginTime;e=1-d/b.controlsFadeLength;e=Math.min(1,e);e=Math.max(0,e);for(f=b.controls.length-1;f>=0;f--)b.controls[f].autoFade&&b.controls[f].setOpacity(e);e>0&&g(b)}}function j(a){var b;a.controlsShouldFade=!1;for(b=a.controls.length-1;b>=0;b--)a.controls[b].setOpacity(1)}function k(){j(this)}function l(){h(this)}function m(b){if(b.preventDefaultAction||b.ctrl||b.alt||b.meta)return!0;switch(b.keyCode){case 38:b.shift?this.viewport.zoomBy(1.1):this.viewport.panBy(this.viewport.deltaPointsFromPixels(new a.Point(0,-40)));this.viewport.applyConstraints();return!1;case 40:b.shift?this.viewport.zoomBy(.9):this.viewport.panBy(this.viewport.deltaPointsFromPixels(new a.Point(0,40)));this.viewport.applyConstraints();return!1;case 37:this.viewport.panBy(this.viewport.deltaPointsFromPixels(new a.Point(-40,0)));this.viewport.applyConstraints();return!1;case 39:this.viewport.panBy(this.viewport.deltaPointsFromPixels(new a.Point(40,0)));this.viewport.applyConstraints();return!1;default:return!0}}function n(b){if(b.preventDefaultAction||b.ctrl||b.alt||b.meta)return!0;switch(b.keyCode){case 43:case 61:this.viewport.zoomBy(1.1);this.viewport.applyConstraints();return!1;case 45:this.viewport.zoomBy(.9);this.viewport.applyConstraints();return!1;case 48:this.viewport.goHome();this.viewport.applyConstraints();return!1;case 119:case 87:b.shift?this.viewport.zoomBy(1.1):this.viewport.panBy(this.viewport.deltaPointsFromPixels(new a.Point(0,-40)));this.viewport.applyConstraints();return!1;case 115:case 83:b.shift?this.viewport.zoomBy(.9):this.viewport.panBy(this.viewport.deltaPointsFromPixels(new a.Point(0,40)));this.viewport.applyConstraints();return!1;case 97:this.viewport.panBy(this.viewport.deltaPointsFromPixels(new a.Point(-40,0)));this.viewport.applyConstraints();return!1;case 100:this.viewport.panBy(this.viewport.deltaPointsFromPixels(new a.Point(40,0)));this.viewport.applyConstraints();return!1;default:return!0}}function o(a){var b;var c=document.activeElement==this.canvas;c||this.canvas.focus();var d={tracker:a.eventSource,position:a.position,quick:a.quick,shift:a.shift,originalEvent:a.originalEvent,preventDefaultAction:a.preventDefaultAction};this.raiseEvent("canvas-click",d);if(!d.preventDefaultAction&&this.viewport&&a.quick){b=this.gestureSettingsByDeviceType(a.pointerType);if(b.clickToZoom){this.viewport.zoomBy(a.shift?1/this.zoomPerClick:this.zoomPerClick,this.viewport.pointFromPixel(a.position,!0));this.viewport.applyConstraints()}}}function p(a){var b;if(!a.preventDefaultAction&&this.viewport){b=this.gestureSettingsByDeviceType(a.pointerType);if(b.dblClickToZoom){this.viewport.zoomBy(a.shift?1/this.zoomPerClick:this.zoomPerClick,this.viewport.pointFromPixel(a.position,!0));this.viewport.applyConstraints()}}this.raiseEvent("canvas-double-click",{tracker:a.eventSource,position:a.position,shift:a.shift,originalEvent:a.originalEvent})}function q(a){var b;var c={tracker:a.eventSource,position:a.position,delta:a.delta,speed:a.speed,direction:a.direction,shift:a.shift,originalEvent:a.originalEvent,preventDefaultAction:a.preventDefaultAction};this.raiseEvent("canvas-drag",c);if(!c.preventDefaultAction&&this.viewport){b=this.gestureSettingsByDeviceType(a.pointerType);this.panHorizontal||(a.delta.x=0);this.panVertical||(a.delta.y=0);if(this.constrainDuringPan){var d=this.viewport.deltaPointsFromPixels(a.delta.negate());this.viewport.centerSpringX.target.value+=d.x;this.viewport.centerSpringY.target.value+=d.y;var e=this.viewport.getBounds();var f=this.viewport.getConstrainedBounds();this.viewport.centerSpringX.target.value-=d.x;this.viewport.centerSpringY.target.value-=d.y;e.x!=f.x&&(a.delta.x=0);e.y!=f.y&&(a.delta.y=0)}this.viewport.panBy(this.viewport.deltaPointsFromPixels(a.delta.negate()),b.flickEnabled&&!this.constrainDuringPan)}}function r(b){if(!b.preventDefaultAction&&this.viewport){var c=this.gestureSettingsByDeviceType(b.pointerType);if(c.flickEnabled&&b.speed>=c.flickMinSpeed){var d=0;this.panHorizontal&&(d=c.flickMomentum*b.speed*Math.cos(b.direction));var e=0;this.panVertical&&(e=c.flickMomentum*b.speed*Math.sin(b.direction));var f=this.viewport.pixelFromPoint(this.viewport.getCenter(!0));var g=this.viewport.pointFromPixel(new a.Point(f.x-d,f.y-e)); +this.viewport.panTo(g,!1)}this.viewport.applyConstraints()}this.raiseEvent("canvas-drag-end",{tracker:b.eventSource,position:b.position,speed:b.speed,direction:b.direction,shift:b.shift,originalEvent:b.originalEvent})}function s(a){this.raiseEvent("canvas-enter",{tracker:a.eventSource,pointerType:a.pointerType,position:a.position,buttons:a.buttons,pointers:a.pointers,insideElementPressed:a.insideElementPressed,buttonDownAny:a.buttonDownAny,originalEvent:a.originalEvent})}function t(b){window.location!=window.parent.location&&a.MouseTracker.resetAllMouseTrackers();this.raiseEvent("canvas-exit",{tracker:b.eventSource,pointerType:b.pointerType,position:b.position,buttons:b.buttons,pointers:b.pointers,insideElementPressed:b.insideElementPressed,buttonDownAny:b.buttonDownAny,originalEvent:b.originalEvent})}function u(a){this.raiseEvent("canvas-press",{tracker:a.eventSource,pointerType:a.pointerType,position:a.position,insideElementPressed:a.insideElementPressed,insideElementReleased:a.insideElementReleased,originalEvent:a.originalEvent})}function v(a){this.raiseEvent("canvas-release",{tracker:a.eventSource,pointerType:a.pointerType,position:a.position,insideElementPressed:a.insideElementPressed,insideElementReleased:a.insideElementReleased,originalEvent:a.originalEvent})}function w(a){this.raiseEvent("canvas-nonprimary-press",{tracker:a.eventSource,position:a.position,pointerType:a.pointerType,button:a.button,buttons:a.buttons,originalEvent:a.originalEvent})}function x(a){this.raiseEvent("canvas-nonprimary-release",{tracker:a.eventSource,position:a.position,pointerType:a.pointerType,button:a.button,buttons:a.buttons,originalEvent:a.originalEvent})}function y(a){var b,c,d,e;if(!a.preventDefaultAction&&this.viewport){b=this.gestureSettingsByDeviceType(a.pointerType);if(b.pinchToZoom){c=this.viewport.pointFromPixel(a.center,!0);d=this.viewport.pointFromPixel(a.lastCenter,!0);e=d.minus(c);this.panHorizontal||(e.x=0);this.panVertical||(e.y=0);this.viewport.zoomBy(a.distance/a.lastDistance,c,!0);this.viewport.panBy(e,!0);this.viewport.applyConstraints()}if(b.pinchRotate){var f=Math.atan2(a.gesturePoints[0].currentPos.y-a.gesturePoints[1].currentPos.y,a.gesturePoints[0].currentPos.x-a.gesturePoints[1].currentPos.x);var g=Math.atan2(a.gesturePoints[0].lastPos.y-a.gesturePoints[1].lastPos.y,a.gesturePoints[0].lastPos.x-a.gesturePoints[1].lastPos.x);this.viewport.setRotation(this.viewport.getRotation()+(f-g)*(180/Math.PI))}}this.raiseEvent("canvas-pinch",{tracker:a.eventSource,gesturePoints:a.gesturePoints,lastCenter:a.lastCenter,center:a.center,lastDistance:a.lastDistance,distance:a.distance,shift:a.shift,originalEvent:a.originalEvent});return!1}function z(b){var c,d,e,f;e=a.now();f=e-this._lastScrollTime;if(f>this.minScrollDeltaTime){this._lastScrollTime=e;if(!b.preventDefaultAction&&this.viewport){c=this.gestureSettingsByDeviceType(b.pointerType);if(c.scrollToZoom){d=Math.pow(this.zoomPerScroll,b.scroll);this.viewport.zoomBy(d,this.viewport.pointFromPixel(b.position,!0));this.viewport.applyConstraints()}}this.raiseEvent("canvas-scroll",{tracker:b.eventSource,position:b.position,scroll:b.scroll,shift:b.shift,originalEvent:b.originalEvent});if(c&&c.scrollToZoom)return!1}else{c=this.gestureSettingsByDeviceType(b.pointerType);if(c&&c.scrollToZoom)return!1}}function A(a){U[this.hash].mouseInside=!0;j(this);this.raiseEvent("container-enter",{tracker:a.eventSource,position:a.position,buttons:a.buttons,pointers:a.pointers,insideElementPressed:a.insideElementPressed,buttonDownAny:a.buttonDownAny,originalEvent:a.originalEvent})}function B(a){if(a.pointers<1){U[this.hash].mouseInside=!1;U[this.hash].animating||h(this)}this.raiseEvent("container-exit",{tracker:a.eventSource,position:a.position,buttons:a.buttons,pointers:a.pointers,insideElementPressed:a.insideElementPressed,buttonDownAny:a.buttonDownAny,originalEvent:a.originalEvent})}function C(a){D(a);a.isOpen()?a._updateRequestId=f(a,C):a._updateRequestId=!1}function D(a){if(!a._opening){if(a.autoResize){var c=b(a.container);var d=U[a.hash].prevContainerSize;if(!c.equals(d)){var e=a.viewport;if(a.preserveImageSizeOnResize){var f=d.x/c.x;var g=e.getZoom()*f;var i=e.getCenter();e.resize(c,!1);e.zoomTo(g,null,!0);e.panTo(i,!0)}else{var k=e.getBounds();e.resize(c,!0);e.fitBoundsWithConstraints(k,!0)}U[a.hash].prevContainerSize=c;U[a.hash].forceRedraw=!0}}var l=a.viewport.update();var m=a.world.update()||l;l&&a.raiseEvent("viewport-change");a.referenceStrip&&(m=a.referenceStrip.update(a.viewport)||m);if(!U[a.hash].animating&&m){a.raiseEvent("animation-start");j(a)}if(m||U[a.hash].forceRedraw||a.world.needsDraw()){E(a);a._drawOverlays();a.navigator&&a.navigator.update(a.viewport);U[a.hash].forceRedraw=!1;m&&a.raiseEvent("animation")}if(U[a.hash].animating&&!m){a.raiseEvent("animation-finish");U[a.hash].mouseInside||h(a)}U[a.hash].animating=m}}function E(a){a.imageLoader.clear();a.drawer.clear();a.world.draw();a.raiseEvent("update-viewport",{})}function F(a,b){return a?a+b:b}function G(){U[this.hash].lastZoomTime=a.now();U[this.hash].zoomFactor=this.zoomPerSecond;U[this.hash].zooming=!0;J(this)}function H(){U[this.hash].lastZoomTime=a.now();U[this.hash].zoomFactor=1/this.zoomPerSecond;U[this.hash].zooming=!0;J(this)}function I(){U[this.hash].zooming=!1}function J(b){a.requestAnimationFrame(a.delegate(b,K))}function K(){var b,c,d;if(U[this.hash].zooming&&this.viewport){b=a.now();c=b-U[this.hash].lastZoomTime;d=Math.pow(U[this.hash].zoomFactor,c/1e3);this.viewport.zoomBy(d);this.viewport.applyConstraints();U[this.hash].lastZoomTime=b;J(this)}}function L(){if(this.viewport){U[this.hash].zooming=!1;this.viewport.zoomBy(this.zoomPerClick/1);this.viewport.applyConstraints()}}function M(){if(this.viewport){U[this.hash].zooming=!1;this.viewport.zoomBy(1/this.zoomPerClick);this.viewport.applyConstraints()}}function N(){this.buttons.emulateEnter();this.buttons.emulateExit()}function O(){this.viewport&&this.viewport.goHome()}function P(){this.isFullPage()&&!a.isFullScreen()?this.setFullPage(!1):this.setFullScreen(!this.isFullPage());this.buttons&&this.buttons.emulateExit();this.fullPageButton.element.focus();this.viewport&&this.viewport.applyConstraints()}function Q(){if(this.viewport){var a=this.viewport.getRotation();0===a?a=270:a-=90;this.viewport.setRotation(a)}}function R(){if(this.viewport){var a=this.viewport.getRotation();270===a?a=0:a+=90;this.viewport.setRotation(a)}}function S(){var a=this._sequenceIndex-1;this.navPrevNextWrap&&a<0&&(a+=this.tileSources.length);this.goToPage(a)}function T(){var a=this._sequenceIndex+1;this.navPrevNextWrap&&a>=this.tileSources.length&&(a=0);this.goToPage(a)}var U={};var V=1;a.Viewer=function(c){var d,e=arguments,g=this;a.isPlainObject(c)||(c={id:e[0],xmlPath:e.length>1?e[1]:void 0,prefixUrl:e.length>2?e[2]:void 0,controls:e.length>3?e[3]:void 0,overlays:e.length>4?e[4]:void 0});if(c.config){a.extend(!0,c,c.config);delete c.config}a.extend(!0,this,{id:c.id,hash:c.hash||V++,initialPage:0,element:null,container:null,canvas:null,overlays:[],overlaysContainer:null,previousBody:[],customControls:[],source:null,drawer:null,world:null,viewport:null,navigator:null,collectionViewport:null,collectionDrawer:null,navImages:null,buttons:null,profiler:null},a.DEFAULT_SETTINGS,c);if("undefined"==typeof this.hash)throw new Error("A hash must be defined, either by specifying options.id or options.hash.");"undefined"!=typeof U[this.hash]&&a.console.warn("Hash "+this.hash+" has already been used.");U[this.hash]={fsBoundsDelta:new a.Point(1,1),prevContainerSize:null,animating:!1,forceRedraw:!1,mouseInside:!1,group:null,zooming:!1,zoomFactor:null,lastZoomTime:null,fullPage:!1,onfullscreenchange:null};this._sequenceIndex=0;this._firstOpen=!0;this._updateRequestId=null;this._loadQueue=[];this.currentOverlays=[];this._lastScrollTime=a.now();a.EventSource.call(this);this.addHandler("open-failed",function(b){var c=a.getString("Errors.OpenFailed",b.eventSource,b.message);g._showMessage(c)});a.ControlDock.call(this,c);this.xmlPath&&(this.tileSources=[this.xmlPath]);this.element=this.element||document.getElementById(this.id);this.canvas=a.makeNeutralElement("div");this.canvas.className="openseadragon-canvas";!function(a){a.width="100%";a.height="100%";a.overflow="hidden";a.position="absolute";a.top="0px";a.left="0px"}(this.canvas.style);a.setElementTouchActionNone(this.canvas);""!==c.tabIndex&&(this.canvas.tabIndex=void 0===c.tabIndex?0:c.tabIndex);this.container.className="openseadragon-container";!function(a){a.width="100%";a.height="100%";a.position="relative";a.overflow="hidden";a.left="0px";a.top="0px";a.textAlign="left"}(this.container.style);this.container.insertBefore(this.canvas,this.container.firstChild);this.element.appendChild(this.container);this.bodyWidth=document.body.style.width;this.bodyHeight=document.body.style.height;this.bodyOverflow=document.body.style.overflow;this.docOverflow=document.documentElement.style.overflow;this.innerTracker=new a.MouseTracker({element:this.canvas,startDisabled:!this.mouseNavEnabled,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,dblClickTimeThreshold:this.dblClickTimeThreshold,dblClickDistThreshold:this.dblClickDistThreshold,keyDownHandler:a.delegate(this,m),keyHandler:a.delegate(this,n),clickHandler:a.delegate(this,o),dblClickHandler:a.delegate(this,p),dragHandler:a.delegate(this,q),dragEndHandler:a.delegate(this,r),enterHandler:a.delegate(this,s),exitHandler:a.delegate(this,t),pressHandler:a.delegate(this,u),releaseHandler:a.delegate(this,v),nonPrimaryPressHandler:a.delegate(this,w),nonPrimaryReleaseHandler:a.delegate(this,x),scrollHandler:a.delegate(this,z),pinchHandler:a.delegate(this,y)});this.outerTracker=new a.MouseTracker({element:this.container,startDisabled:!this.mouseNavEnabled,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,dblClickTimeThreshold:this.dblClickTimeThreshold,dblClickDistThreshold:this.dblClickDistThreshold,enterHandler:a.delegate(this,A),exitHandler:a.delegate(this,B)});this.toolbar&&(this.toolbar=new a.ControlDock({element:this.toolbar}));this.bindStandardControls();U[this.hash].prevContainerSize=b(this.container);this.world=new a.World({viewer:this});this.world.addHandler("add-item",function(a){g.source=g.world.getItemAt(0).source;U[g.hash].forceRedraw=!0;g._updateRequestId||(g._updateRequestId=f(g,C))});this.world.addHandler("remove-item",function(a){g.world.getItemCount()?g.source=g.world.getItemAt(0).source:g.source=null;U[g.hash].forceRedraw=!0});this.world.addHandler("metrics-change",function(a){g.viewport&&g.viewport._setContentBounds(g.world.getHomeBounds(),g.world.getContentFactor())});this.world.addHandler("item-index-change",function(a){g.source=g.world.getItemAt(0).source});this.viewport=new a.Viewport({containerSize:U[this.hash].prevContainerSize,springStiffness:this.springStiffness,animationTime:this.animationTime,minZoomImageRatio:this.minZoomImageRatio,maxZoomPixelRatio:this.maxZoomPixelRatio,visibilityRatio:this.visibilityRatio,wrapHorizontal:this.wrapHorizontal,wrapVertical:this.wrapVertical,defaultZoomLevel:this.defaultZoomLevel,minZoomLevel:this.minZoomLevel,maxZoomLevel:this.maxZoomLevel,viewer:this,degrees:this.degrees,navigatorRotate:this.navigatorRotate,homeFillsViewer:this.homeFillsViewer,margins:this.viewportMargins});this.viewport._setContentBounds(this.world.getHomeBounds(),this.world.getContentFactor());this.imageLoader=new a.ImageLoader({jobLimit:this.imageLoaderLimit,timeout:c.timeout});this.tileCache=new a.TileCache({maxImageCacheCount:this.maxImageCacheCount});this.drawer=new a.Drawer({viewer:this,viewport:this.viewport,element:this.canvas,debugGridColor:this.debugGridColor});this.overlaysContainer=a.makeNeutralElement("div");this.canvas.appendChild(this.overlaysContainer);if(!this.drawer.canRotate()){if(this.rotateLeft){d=this.buttons.buttons.indexOf(this.rotateLeft);this.buttons.buttons.splice(d,1);this.buttons.element.removeChild(this.rotateLeft.element)}if(this.rotateRight){d=this.buttons.buttons.indexOf(this.rotateRight);this.buttons.buttons.splice(d,1);this.buttons.element.removeChild(this.rotateRight.element)}}this.showNavigator&&(this.navigator=new a.Navigator({id:this.navigatorId,position:this.navigatorPosition,sizeRatio:this.navigatorSizeRatio,maintainSizeRatio:this.navigatorMaintainSizeRatio,top:this.navigatorTop,left:this.navigatorLeft,width:this.navigatorWidth,height:this.navigatorHeight,autoResize:this.navigatorAutoResize,autoFade:this.navigatorAutoFade,prefixUrl:this.prefixUrl,viewer:this,navigatorRotate:this.navigatorRotate,crossOriginPolicy:this.crossOriginPolicy}));this.sequenceMode&&this.bindSequenceControls();this.tileSources&&this.open(this.tileSources);for(d=0;d-1&&b.index=0&&a=0)return this;var i=d(this,h);this.currentOverlays.push(i);i.drawHTML(this.overlaysContainer,this.viewport);this.raiseEvent("add-overlay",{element:b,location:h.location,placement:h.placement});return this},updateOverlay:function(b,c,d){var f;b=a.getElement(b);f=e(this.currentOverlays,b);if(f>=0){this.currentOverlays[f].update(c,d);U[this.hash].forceRedraw=!0;this.raiseEvent("update-overlay",{element:b,location:c,placement:d})}return this; +},removeOverlay:function(b){var c;b=a.getElement(b);c=e(this.currentOverlays,b);if(c>=0){this.currentOverlays[c].destroy();this.currentOverlays.splice(c,1);U[this.hash].forceRedraw=!0;this.raiseEvent("remove-overlay",{element:b})}return this},clearOverlays:function(){for(;this.currentOverlays.length>0;)this.currentOverlays.pop().destroy();U[this.hash].forceRedraw=!0;this.raiseEvent("clear-overlay",{});return this},getOverlayById:function(b){var c;b=a.getElement(b);c=e(this.currentOverlays,b);return c>=0?this.currentOverlays[c]:null},_updateSequenceButtons:function(a){this.nextButton&&(this.tileSources&&this.tileSources.length-1!==a?this.nextButton.enable():this.navPrevNextWrap||this.nextButton.disable());this.previousButton&&(a>0?this.previousButton.enable():this.navPrevNextWrap||this.previousButton.disable())},_showMessage:function(b){this._hideMessage();var c=a.makeNeutralElement("div");c.appendChild(document.createTextNode(b));this.messageDiv=a.makeCenteredNode(c);a.addClass(this.messageDiv,"openseadragon-message");this.container.appendChild(this.messageDiv)},_hideMessage:function(){var a=this.messageDiv;if(a){a.parentNode.removeChild(a);delete this.messageDiv}},gestureSettingsByDeviceType:function(a){switch(a){case"mouse":return this.gestureSettingsMouse;case"touch":return this.gestureSettingsTouch;case"pen":return this.gestureSettingsPen;default:return this.gestureSettingsUnknown}},_drawOverlays:function(){var a,b=this.currentOverlays.length;for(a=0;a1){this.referenceStrip=new a.ReferenceStrip({id:this.referenceStripElement,position:this.referenceStripPosition,sizeRatio:this.referenceStripSizeRatio,scroll:this.referenceStripScroll,height:this.referenceStripHeight,width:this.referenceStripWidth,tileSources:this.tileSources,prefixUrl:this.prefixUrl,viewer:this});this.referenceStrip.setFocus(this._sequenceIndex)}}else a.console.warn('Attempting to display a reference strip while "sequenceMode" is off.')}})}(OpenSeadragon);!function(a){function b(a){if(a.quick&&this.viewer.viewport){this.viewer.viewport.panTo(this.viewport.pointFromPixel(a.position));this.viewer.viewport.applyConstraints()}}function c(a){if(this.viewer.viewport){this.panHorizontal||(a.delta.x=0);this.panVertical||(a.delta.y=0);this.viewer.viewport.panBy(this.viewport.deltaPointsFromPixels(a.delta));this.viewer.constrainDuringPan&&this.viewer.viewport.applyConstraints()}}function d(a){a.insideElementPressed&&this.viewer.viewport&&this.viewer.viewport.applyConstraints()}function e(a){this.viewer.raiseEvent("navigator-scroll",{tracker:a.eventSource,position:a.position,scroll:a.scroll,shift:a.shift,originalEvent:a.originalEvent});return!1}function f(a,b){a.style.webkitTransform="rotate("+b+"deg)";a.style.mozTransform="rotate("+b+"deg)";a.style.msTransform="rotate("+b+"deg)";a.style.oTransform="rotate("+b+"deg)";a.style.transform="rotate("+b+"deg)"}a.Navigator=function(g){function h(a){f(l.displayRegionContainer,a);f(l.displayRegion,-a);l.viewport.setRotation(a)}var i,j,k=g.viewer,l=this;if(g.id){this.element=document.getElementById(g.id);g.controlOptions={anchor:a.ControlAnchor.NONE,attachToViewer:!1,autoFade:!1}}else{g.id="navigator-"+a.now();this.element=a.makeNeutralElement("div");g.controlOptions={anchor:a.ControlAnchor.TOP_RIGHT,attachToViewer:!0,autoFade:g.autoFade};if(g.position)if("BOTTOM_RIGHT"==g.position)g.controlOptions.anchor=a.ControlAnchor.BOTTOM_RIGHT;else if("BOTTOM_LEFT"==g.position)g.controlOptions.anchor=a.ControlAnchor.BOTTOM_LEFT;else if("TOP_RIGHT"==g.position)g.controlOptions.anchor=a.ControlAnchor.TOP_RIGHT;else if("TOP_LEFT"==g.position)g.controlOptions.anchor=a.ControlAnchor.TOP_LEFT;else if("ABSOLUTE"==g.position){g.controlOptions.anchor=a.ControlAnchor.ABSOLUTE;g.controlOptions.top=g.top;g.controlOptions.left=g.left;g.controlOptions.height=g.height;g.controlOptions.width=g.width}}this.element.id=g.id;this.element.className+=" navigator";g=a.extend(!0,{sizeRatio:a.DEFAULT_SETTINGS.navigatorSizeRatio},g,{element:this.element,tabIndex:-1,showNavigator:!1,mouseNavEnabled:!1,showNavigationControl:!1,showSequenceControl:!1,immediateRender:!0,blendTime:0,animationTime:0,autoResize:g.autoResize,minZoomImageRatio:1});g.minPixelRatio=this.minPixelRatio=k.minPixelRatio;a.setElementTouchActionNone(this.element);this.borderWidth=2;this.fudge=new a.Point(1,1);this.totalBorderWidths=new a.Point(2*this.borderWidth,2*this.borderWidth).minus(this.fudge);g.controlOptions.anchor!=a.ControlAnchor.NONE&&!function(a,b){a.margin="0px";a.border=b+"px solid #555";a.padding="0px";a.background="#000";a.opacity=.8;a.overflow="hidden"}(this.element.style,this.borderWidth);this.displayRegion=a.makeNeutralElement("div");this.displayRegion.id=this.element.id+"-displayregion";this.displayRegion.className="displayregion";!function(a,b){a.position="relative";a.top="0px";a.left="0px";a.fontSize="0px";a.overflow="hidden";a.border=b+"px solid #900";a.margin="0px";a.padding="0px";a.background="transparent";a.float="left";a.cssFloat="left";a.styleFloat="left";a.zIndex=999999999;a.cursor="default"}(this.displayRegion.style,this.borderWidth);this.displayRegionContainer=a.makeNeutralElement("div");this.displayRegionContainer.id=this.element.id+"-displayregioncontainer";this.displayRegionContainer.className="displayregioncontainer";this.displayRegionContainer.style.width="100%";this.displayRegionContainer.style.height="100%";k.addControl(this.element,g.controlOptions);this._resizeWithViewer=g.controlOptions.anchor!=a.ControlAnchor.ABSOLUTE&&g.controlOptions.anchor!=a.ControlAnchor.NONE;if(this._resizeWithViewer){if(g.width&&g.height){this.element.style.height="number"==typeof g.height?g.height+"px":g.height;this.element.style.width="number"==typeof g.width?g.width+"px":g.width}else{i=a.getElementSize(k.element);this.element.style.height=Math.round(i.y*g.sizeRatio)+"px";this.element.style.width=Math.round(i.x*g.sizeRatio)+"px";this.oldViewerSize=i}j=a.getElementSize(this.element);this.elementArea=j.x*j.y}this.oldContainerSize=new a.Point(0,0);a.Viewer.apply(this,[g]);this.displayRegionContainer.appendChild(this.displayRegion);this.element.getElementsByTagName("div")[0].appendChild(this.displayRegionContainer);if(g.navigatorRotate){var m=g.viewer.viewport?g.viewer.viewport.getRotation():g.viewer.degrees||0;h(m);g.viewer.addHandler("rotate",function(a){h(a.degrees)})}this.innerTracker.destroy();this.innerTracker=new a.MouseTracker({element:this.element,dragHandler:a.delegate(this,c),clickHandler:a.delegate(this,b),releaseHandler:a.delegate(this,d),scrollHandler:a.delegate(this,e)});this.addHandler("reset-size",function(){l.viewport&&l.viewport.goHome(!0)});k.world.addHandler("item-index-change",function(a){window.setTimeout(function(){var b=l.world.getItemAt(a.previousIndex);l.world.setItemIndex(b,a.newIndex)},1)});k.world.addHandler("remove-item",function(a){var b=a.item;var c=l._getMatchingItem(b);c&&l.world.removeItem(c)});this.update(k.viewport)};a.extend(a.Navigator.prototype,a.EventSource.prototype,a.Viewer.prototype,{updateSize:function(){if(this.viewport){var b=new a.Point(0===this.container.clientWidth?1:this.container.clientWidth,0===this.container.clientHeight?1:this.container.clientHeight);if(!b.equals(this.oldContainerSize)){this.viewport.resize(b,!0);this.viewport.goHome(!0);this.oldContainerSize=b;this.drawer.clear();this.world.draw()}}},update:function(b){var c,d,e,f,g,h;c=a.getElementSize(this.viewer.element);if(this._resizeWithViewer&&c.x&&c.y&&!c.equals(this.oldViewerSize)){this.oldViewerSize=c;if(this.maintainSizeRatio||!this.elementArea){d=c.x*this.sizeRatio;e=c.y*this.sizeRatio}else{d=Math.sqrt(this.elementArea*(c.x/c.y));e=this.elementArea/d}this.element.style.width=Math.round(d)+"px";this.element.style.height=Math.round(e)+"px";this.elementArea||(this.elementArea=d*e);this.updateSize()}if(b&&this.viewport){f=b.getBoundsNoRotate(!0);g=this.viewport.pixelFromPointNoRotate(f.getTopLeft(),!1);h=this.viewport.pixelFromPointNoRotate(f.getBottomRight(),!1).minus(this.totalBorderWidths);var i=this.displayRegion.style;i.display=this.world.getItemCount()?"block":"none";i.top=Math.round(g.y)+"px";i.left=Math.round(g.x)+"px";var j=Math.abs(g.x-h.x);var k=Math.abs(g.y-h.y);i.width=Math.round(Math.max(j,0))+"px";i.height=Math.round(Math.max(k,0))+"px"}},addTiledImage:function(b){var c=this;var d=b.originalTiledImage;delete b.original;var e=a.extend({},b,{success:function(a){function b(){c._matchBounds(g,d)}function e(){c._matchOpacity(g,d)}function f(){c._matchCompositeOperation(g,d)}var g=a.item;g._originalForNavigator=d;c._matchBounds(g,d,!0);d.addHandler("bounds-change",b);d.addHandler("clip-change",b);d.addHandler("opacity-change",e);d.addHandler("composite-operation-change",f)}});return a.Viewer.prototype.addTiledImage.apply(this,[e])},_getMatchingItem:function(a){var b=this.world.getItemCount();var c;for(var d=0;d1||b.y>1)break}return a-1},getTileAtPoint:function(b,c){var d=c.x>=0&&c.x<=1&&c.y>=0&&c.y<=1/this.aspectRatio;a.console.assert(d,"[TileSource.getTileAtPoint] must be called with a valid point.");var e=this.dimensions.x*this.getLevelScale(b);var f=c.x*e;var g=c.y*e;var h=Math.floor(f/this.getTileWidth(b));var i=Math.floor(g/this.getTileHeight(b));c.x>=1&&(h=this.getNumTiles(b).x-1);var j=1e-16;c.y>=1/this.aspectRatio-j&&(i=this.getNumTiles(b).y-1);return new a.Point(h,i)},getTileBounds:function(b,c,d){var e=this.dimensions.times(this.getLevelScale(b)),f=this.getTileWidth(b),g=this.getTileHeight(b),h=0===c?0:f*c-this.tileOverlap,i=0===d?0:g*d-this.tileOverlap,j=f+(0===c?1:2)*this.tileOverlap,k=g+(0===d?1:2)*this.tileOverlap,l=1/e.x;j=Math.min(j,e.x-h);k=Math.min(k,e.y-i);return new a.Rect(h*l,i*l,j*l,k*l)},getImageInfo:function(c){var d,e,f,g,h,i,j,k=this;if(c){h=c.split("/");i=h[h.length-1];j=i.lastIndexOf(".");j>-1&&(h[h.length-1]=i.slice(0,j))}e=function(b){"string"==typeof b&&(b=a.parseXml(b));var d=a.TileSource.determineType(k,b,c);if(d){g=d.prototype.configure.apply(k,[b,c]);void 0===g.ajaxWithCredentials&&(g.ajaxWithCredentials=k.ajaxWithCredentials);f=new d(g);k.ready=!0;k.raiseEvent("ready",{tileSource:f})}else k.raiseEvent("open-failed",{message:"Unable to load TileSource",source:c})};if(c.match(/\.js$/)){d=c.split("/").pop().replace(".js","");a.jsonp({url:c,async:!1,callbackName:d,callback:e})}else a.makeAjaxRequest({url:c,withCredentials:this.ajaxWithCredentials,headers:this.ajaxHeaders,success:function(a){var c=b(a);e(c)},error:function(a,b){var d;try{d="HTTP "+a.status+" attempting to load TileSource"}catch(a){var e;e="undefined"!=typeof b&&b.toString?b.toString():"Unknown error";d=e+" attempting to load TileSource"}k.raiseEvent("open-failed",{message:d,source:c})}})},supports:function(a,b){return!1},configure:function(a,b){throw new Error("Method not implemented.")},getTileUrl:function(a,b,c){throw new Error("Method not implemented.")},getTileAjaxHeaders:function(a,b,c){return{}},tileExists:function(a,b,c){var d=this.getNumTiles(a);return a>=this.minLevel&&a<=this.maxLevel&&b>=0&&c>=0&&b=0;k--){l=this.displayRects[k];for(m=l.minLevel;m<=l.maxLevel;m++){this._levelRects[m]||(this._levelRects[m]=[]);this._levelRects[m].push(l)}}a.TileSource.apply(this,[n])};a.extend(a.DziTileSource.prototype,a.TileSource.prototype,{supports:function(a,b){var c;a.Image?c=a.Image.xmlns:a.documentElement&&("Image"!=a.documentElement.localName&&"Image"!=a.documentElement.tagName||(c=a.documentElement.namespaceURI));c=(c||"").toLowerCase();return c.indexOf("schemas.microsoft.com/deepzoom/2008")!==-1||c.indexOf("schemas.microsoft.com/deepzoom/2009")!==-1},configure:function(d,e){var f;f=a.isPlainObject(d)?c(this,d):b(this,d);if(e&&!f.tilesUrl){f.tilesUrl=e.replace(/([^\/]+?)(\.(dzi|xml|js)?(\?[^\/]*)?)?\/?$/,"$1_files/");e.search(/\.(dzi|xml|js)\?/)!=-1?f.queryParams=e.match(/\?.*/):f.queryParams=""}return f},getTileUrl:function(a,b,c){return[this.tilesUrl,a,"/",b,"_",c,".",this.fileFormat,this.queryParams].join("")},tileExists:function(a,b,c){var d,e,f,g,h,i,j,k=this._levelRects[a];if(!k||!k.length)return!0;for(j=k.length-1;j>=0;j--){d=k[j];if(!(ad.maxLevel)){e=this.getLevelScale(a);f=d.x*e;g=d.y*e;h=f+d.width*e;i=g+d.height*e;f=Math.floor(f/this._tileWidth);g=Math.floor(g/this._tileWidth);h=Math.ceil(h/this._tileWidth);i=Math.ceil(i/this._tileWidth);if(f<=b&&b0?d.tileSize=Math.max.apply(null,j):d.tileSize=h}else if(this.sizes&&this.sizes.length>0){this.emulateLegacyImagePyramid=!0;d.levels=c(this);a.extend(!0,d,{width:d.levels[d.levels.length-1].width,height:d.levels[d.levels.length-1].height,tileSize:Math.max(d.height,d.width),tileOverlap:0,minLevel:0,maxLevel:d.levels.length-1});this.levels=d.levels}else a.console.error("Nothing in the info.json to construct image pyramids from");d.maxLevel||this.emulateLegacyImagePyramid||(this.scale_factors?d.maxLevel=Math.floor(Math.pow(Math.max.apply(null,this.scale_factors),.5)):d.maxLevel=Number(Math.ceil(Math.log(Math.max(this.width,this.height),2))));a.TileSource.apply(this,[d])};a.extend(a.IIIFTileSource.prototype,a.TileSource.prototype,{supports:function(a,b){return!(!a.protocol||"http://iiif.io/api/image"!=a.protocol)||(!(!a["@context"]||"http://library.stanford.edu/iiif/image-api/1.1/context.json"!=a["@context"]&&"http://iiif.io/api/image/1/context.json"!=a["@context"])||(!(!a.profile||0!==a.profile.indexOf("http://library.stanford.edu/iiif/image-api/compliance.html"))||(!!(a.identifier&&a.width&&a.height)||!(!a.documentElement||"info"!=a.documentElement.tagName||"http://library.stanford.edu/iiif/image-api/ns/"!=a.documentElement.namespaceURI))))},configure:function(b,c){if(a.isPlainObject(b)){if(b["@context"])return b;b["@context"]="http://iiif.io/api/image/1.0/context.json";b["@id"]=c.replace("/info.json","");return b}var e=d(b);e["@context"]="http://iiif.io/api/image/1.0/context.json";e["@id"]=c.replace("/info.xml","");return e},getTileWidth:function(b){if(this.emulateLegacyImagePyramid)return a.TileSource.prototype.getTileWidth.call(this,b);var c=Math.pow(2,this.maxLevel-b);return this.tileSizePerScaleFactor&&this.tileSizePerScaleFactor[c]?this.tileSizePerScaleFactor[c].width:this._tileWidth},getTileHeight:function(b){if(this.emulateLegacyImagePyramid)return a.TileSource.prototype.getTileHeight.call(this,b);var c=Math.pow(2,this.maxLevel-b);return this.tileSizePerScaleFactor&&this.tileSizePerScaleFactor[c]?this.tileSizePerScaleFactor[c].height:this._tileHeight},getLevelScale:function(b){if(this.emulateLegacyImagePyramid){var c=NaN;this.levels.length>0&&b>=this.minLevel&&b<=this.maxLevel&&(c=this.levels[b].width/this.levels[this.maxLevel].width);return c}return a.TileSource.prototype.getLevelScale.call(this,b)},getNumTiles:function(b){if(this.emulateLegacyImagePyramid){var c=this.getLevelScale(b);return c?new a.Point(1,1):new a.Point(0,0)}return a.TileSource.prototype.getNumTiles.call(this,b)},getTileAtPoint:function(b,c){return this.emulateLegacyImagePyramid?new a.Point(0,0):a.TileSource.prototype.getTileAtPoint.call(this,b,c)},getTileUrl:function(a,b,c){if(this.emulateLegacyImagePyramid){var d=null;this.levels.length>0&&a>=this.minLevel&&a<=this.maxLevel&&(d=this.levels[a].url);return d}var e,f,g,h,i,j,k,l,m,n,o,p,q="0",r=Math.pow(.5,this.maxLevel-a),s=Math.ceil(this.width*r),t=Math.ceil(this.height*r);e=this.getTileWidth(a);f=this.getTileHeight(a);g=Math.ceil(e/r);h=Math.ceil(f/r);o=this["@context"].indexOf("/1.0/context.json")>-1||this["@context"].indexOf("/1.1/context.json")>-1||this["@context"].indexOf("/1/context.json")>-1?"native.jpg":"default.jpg";if(sj?i/256:j/256;g.maxLevel=Math.ceil(Math.log(h)/Math.log(2))-1;g.tileSize=256;g.width=i;g.height=j;a.TileSource.apply(this,[g])};a.extend(a.TmsTileSource.prototype,a.TileSource.prototype,{supports:function(a,b){return a.type&&"tiledmapservice"==a.type},configure:function(a,b){return a},getTileUrl:function(a,b,c){var d=this.getNumTiles(a).y-1;return this.tilesUrl+a+"/"+b+"/"+(d-c)+".png"}})}(OpenSeadragon);!function(a){a.ZoomifyTileSource=function(a){a.tileSize=256;var b={x:a.width,y:a.height};a.imageSizes=[{x:a.width,y:a.height}];a.gridSize=[this._getGridSize(a.width,a.height,a.tileSize)];for(;parseInt(b.x,10)>a.tileSize||parseInt(b.y,10)>a.tileSize;){b.x=Math.floor(b.x/2);b.y=Math.floor(b.y/2);a.imageSizes.push({x:b.x,y:b.y});a.gridSize.push(this._getGridSize(b.x,b.y,a.tileSize))}a.imageSizes.reverse();a.gridSize.reverse();a.minLevel=0;a.maxLevel=a.gridSize.length-1;OpenSeadragon.TileSource.apply(this,[a])};a.extend(a.ZoomifyTileSource.prototype,a.TileSource.prototype,{_getGridSize:function(a,b,c){return{x:Math.ceil(a/c),y:Math.ceil(b/c)}},_calculateAbsoluteTileNumber:function(a,b,c){var d=0;var e={};for(var f=0;f")}return e.sort(function(a,b){return a.height-b.height})}function c(b,c){if(!c||!c.documentElement)throw new Error(a.getString("Errors.Xml"));var e,f,g=c.documentElement,h=g.tagName,i=null,j=[];if("image"==h)try{i={type:g.getAttribute("type"),levels:[]};j=g.getElementsByTagName("level");for(f=0;f0){e=d.levels[d.levels.length-1].width;f=d.levels[d.levels.length-1].height}else{e=0;f=0;a.console.error("No supported image formats found")}a.extend(!0,d,{width:e,height:f,tileSize:Math.max(f,e),tileOverlap:0,minLevel:0,maxLevel:d.levels.length>0?d.levels.length-1:0});a.TileSource.apply(this,[d]);this.levels=d.levels};a.extend(a.LegacyTileSource.prototype,a.TileSource.prototype,{supports:function(a,b){return a.type&&"legacy-image-pyramid"==a.type||a.documentElement&&"legacy-image-pyramid"==a.documentElement.getAttribute("type")},configure:function(b,e){var f;f=a.isPlainObject(b)?d(this,b):c(this,b);return f},getLevelScale:function(a){var b=NaN;this.levels.length>0&&a>=this.minLevel&&a<=this.maxLevel&&(b=this.levels[a].width/this.levels[this.maxLevel].width);return b},getNumTiles:function(b){var c=this.getLevelScale(b);return c?new a.Point(1,1):new a.Point(0,0)},getTileUrl:function(a,b,c){var d=null;this.levels.length>0&&a>=this.minLevel&&a<=this.maxLevel&&(d=this.levels[a].url);return d}})}(OpenSeadragon);!function(a){a.ImageTileSource=function(b){b=a.extend({buildPyramid:!0,crossOriginPolicy:!1,ajaxWithCredentials:!1,useCanvas:!0},b);a.TileSource.apply(this,[b])};a.extend(a.ImageTileSource.prototype,a.TileSource.prototype,{supports:function(a,b){return a.type&&"image"===a.type},configure:function(a,b){return a},getImageInfo:function(b){var c=this._image=new Image;var d=this;this.crossOriginPolicy&&(c.crossOrigin=this.crossOriginPolicy);this.ajaxWithCredentials&&(c.useCredentials=this.ajaxWithCredentials);a.addEvent(c,"load",function(){d.width=Object.prototype.hasOwnProperty.call(c,"naturalWidth")?c.naturalWidth:c.width;d.height=Object.prototype.hasOwnProperty.call(c,"naturalHeight")?c.naturalHeight:c.height;d.aspectRatio=d.width/d.height;d.dimensions=new a.Point(d.width,d.height);d._tileWidth=d.width;d._tileHeight=d.height; +d.tileOverlap=0;d.minLevel=0;d.levels=d._buildLevels();d.maxLevel=d.levels.length-1;d.ready=!0;d.raiseEvent("ready",{tileSource:d})});a.addEvent(c,"error",function(){d.raiseEvent("open-failed",{message:"Error loading image at "+b,source:b})});c.src=b},getLevelScale:function(a){var b=NaN;a>=this.minLevel&&a<=this.maxLevel&&(b=this.levels[a].width/this.levels[this.maxLevel].width);return b},getNumTiles:function(b){var c=this.getLevelScale(b);return c?new a.Point(1,1):new a.Point(0,0)},getTileUrl:function(a,b,c){var d=null;a>=this.minLevel&&a<=this.maxLevel&&(d=this.levels[a].url);return d},getContext2D:function(a,b,c){var d=null;a>=this.minLevel&&a<=this.maxLevel&&(d=this.levels[a].context2D);return d},_buildLevels:function(){var b=[{url:this._image.src,width:Object.prototype.hasOwnProperty.call(this._image,"naturalWidth")?this._image.naturalWidth:this._image.width,height:Object.prototype.hasOwnProperty.call(this._image,"naturalHeight")?this._image.naturalHeight:this._image.height}];if(!this.buildPyramid||!a.supportsCanvas||!this.useCanvas){delete this._image;return b}var c=Object.prototype.hasOwnProperty.call(this._image,"naturalWidth")?this._image.naturalWidth:this._image.width;var d=Object.prototype.hasOwnProperty.call(this._image,"naturalHeight")?this._image.naturalHeight:this._image.height;var e=document.createElement("canvas");var f=e.getContext("2d");e.width=c;e.height=d;f.drawImage(this._image,0,0,c,d);b[0].context2D=f;delete this._image;if(a.isCanvasTainted(e))return b;for(;c>=2&&d>=2;){c=Math.floor(c/2);d=Math.floor(d/2);var g=document.createElement("canvas");var h=g.getContext("2d");g.width=c;g.height=d;h.drawImage(e,0,0,c,d);b.splice(0,0,{context2D:h,width:c,height:d});e=g;f=h}return b}})}(OpenSeadragon);!function(a){a.TileSourceCollection=function(b,c,d,e){a.console.error("TileSourceCollection is deprecated; use World instead")}}(OpenSeadragon);!function(a){function b(b){a.requestAnimationFrame(function(){c(b)})}function c(c){var d,e,f;if(c.shouldFade){d=a.now();e=d-c.fadeBeginTime;f=1-e/c.fadeLength;f=Math.min(1,f);f=Math.max(0,f);c.imgGroup&&a.setElementOpacity(c.imgGroup,f,!0);f>0&&b(c)}}function d(c){c.shouldFade=!0;c.fadeBeginTime=a.now()+c.fadeDelay;window.setTimeout(function(){b(c)},c.fadeDelay)}function e(b){b.shouldFade=!1;b.imgGroup&&a.setElementOpacity(b.imgGroup,1,!0)}function f(b,c){if(!b.element.disabled){if(c>=a.ButtonState.GROUP&&b.currentState==a.ButtonState.REST){e(b);b.currentState=a.ButtonState.GROUP}if(c>=a.ButtonState.HOVER&&b.currentState==a.ButtonState.GROUP){b.imgHover&&(b.imgHover.style.visibility="");b.currentState=a.ButtonState.HOVER}if(c>=a.ButtonState.DOWN&&b.currentState==a.ButtonState.HOVER){b.imgDown&&(b.imgDown.style.visibility="");b.currentState=a.ButtonState.DOWN}}}function g(b,c){if(!b.element.disabled){if(c<=a.ButtonState.HOVER&&b.currentState==a.ButtonState.DOWN){b.imgDown&&(b.imgDown.style.visibility="hidden");b.currentState=a.ButtonState.HOVER}if(c<=a.ButtonState.GROUP&&b.currentState==a.ButtonState.HOVER){b.imgHover&&(b.imgHover.style.visibility="hidden");b.currentState=a.ButtonState.GROUP}if(c<=a.ButtonState.REST&&b.currentState==a.ButtonState.GROUP){d(b);b.currentState=a.ButtonState.REST}}}a.ButtonState={REST:0,GROUP:1,HOVER:2,DOWN:3};a.Button=function(b){var c=this;a.EventSource.call(this);a.extend(!0,this,{tooltip:null,srcRest:null,srcGroup:null,srcHover:null,srcDown:null,clickTimeThreshold:a.DEFAULT_SETTINGS.clickTimeThreshold,clickDistThreshold:a.DEFAULT_SETTINGS.clickDistThreshold,fadeDelay:0,fadeLength:2e3,onPress:null,onRelease:null,onClick:null,onEnter:null,onExit:null,onFocus:null,onBlur:null},b);this.element=b.element||a.makeNeutralElement("div");if(!b.element){this.imgRest=a.makeTransparentImage(this.srcRest);this.imgGroup=a.makeTransparentImage(this.srcGroup);this.imgHover=a.makeTransparentImage(this.srcHover);this.imgDown=a.makeTransparentImage(this.srcDown);this.imgRest.alt=this.imgGroup.alt=this.imgHover.alt=this.imgDown.alt=this.tooltip;this.element.style.position="relative";a.setElementTouchActionNone(this.element);this.imgGroup.style.position=this.imgHover.style.position=this.imgDown.style.position="absolute";this.imgGroup.style.top=this.imgHover.style.top=this.imgDown.style.top="0px";this.imgGroup.style.left=this.imgHover.style.left=this.imgDown.style.left="0px";this.imgHover.style.visibility=this.imgDown.style.visibility="hidden";a.Browser.vendor==a.BROWSERS.FIREFOX&&a.Browser.version<3&&(this.imgGroup.style.top=this.imgHover.style.top=this.imgDown.style.top="");this.element.appendChild(this.imgRest);this.element.appendChild(this.imgGroup);this.element.appendChild(this.imgHover);this.element.appendChild(this.imgDown)}this.addHandler("press",this.onPress);this.addHandler("release",this.onRelease);this.addHandler("click",this.onClick);this.addHandler("enter",this.onEnter);this.addHandler("exit",this.onExit);this.addHandler("focus",this.onFocus);this.addHandler("blur",this.onBlur);this.currentState=a.ButtonState.GROUP;this.fadeBeginTime=null;this.shouldFade=!1;this.element.style.display="inline-block";this.element.style.position="relative";this.element.title=this.tooltip;this.tracker=new a.MouseTracker({element:this.element,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,enterHandler:function(b){if(b.insideElementPressed){f(c,a.ButtonState.DOWN);c.raiseEvent("enter",{originalEvent:b.originalEvent})}else b.buttonDownAny||f(c,a.ButtonState.HOVER)},focusHandler:function(a){this.enterHandler(a);c.raiseEvent("focus",{originalEvent:a.originalEvent})},exitHandler:function(b){g(c,a.ButtonState.GROUP);b.insideElementPressed&&c.raiseEvent("exit",{originalEvent:b.originalEvent})},blurHandler:function(a){this.exitHandler(a);c.raiseEvent("blur",{originalEvent:a.originalEvent})},pressHandler:function(b){f(c,a.ButtonState.DOWN);c.raiseEvent("press",{originalEvent:b.originalEvent})},releaseHandler:function(b){if(b.insideElementPressed&&b.insideElementReleased){g(c,a.ButtonState.HOVER);c.raiseEvent("release",{originalEvent:b.originalEvent})}else b.insideElementPressed?g(c,a.ButtonState.GROUP):f(c,a.ButtonState.HOVER)},clickHandler:function(a){a.quick&&c.raiseEvent("click",{originalEvent:a.originalEvent})},keyHandler:function(a){if(13===a.keyCode){c.raiseEvent("click",{originalEvent:a.originalEvent});c.raiseEvent("release",{originalEvent:a.originalEvent});return!1}return!0}});g(this,a.ButtonState.REST)};a.extend(a.Button.prototype,a.EventSource.prototype,{notifyGroupEnter:function(){f(this,a.ButtonState.GROUP)},notifyGroupExit:function(){g(this,a.ButtonState.REST)},disable:function(){this.notifyGroupExit();this.element.disabled=!0;a.setElementOpacity(this.element,.2,!0)},enable:function(){this.element.disabled=!1;a.setElementOpacity(this.element,1,!0);this.notifyGroupEnter()}})}(OpenSeadragon);!function(a){a.ButtonGroup=function(b){a.extend(!0,this,{buttons:[],clickTimeThreshold:a.DEFAULT_SETTINGS.clickTimeThreshold,clickDistThreshold:a.DEFAULT_SETTINGS.clickDistThreshold,labelText:""},b);var c,d=this.buttons.concat([]),e=this;this.element=b.element||a.makeNeutralElement("div");if(!b.group){this.label=a.makeNeutralElement("label");this.element.style.display="inline-block";this.element.appendChild(this.label);for(c=0;c=270){g=this.getTopRight();this.x=g.x;this.y=g.y;h=this.height;this.height=this.width;this.width=h;this.degrees-=270}else if(this.degrees>=180){g=this.getBottomRight();this.x=g.x;this.y=g.y;this.degrees-=180}else if(this.degrees>=90){g=this.getBottomLeft();this.x=g.x;this.y=g.y;h=this.height;this.height=this.width;this.width=h;this.degrees-=90}};a.Rect.fromSummits=function(b,c,d){var e=b.distanceTo(c);var f=b.distanceTo(d);var g=c.minus(b);var h=Math.atan(g.y/g.x);g.x<0?h+=Math.PI:g.y<0&&(h+=2*Math.PI);return new a.Rect(b.x,b.y,e,f,h/Math.PI*180)};a.Rect.prototype={clone:function(){return new a.Rect(this.x,this.y,this.width,this.height,this.degrees)},getAspectRatio:function(){return this.width/this.height},getTopLeft:function(){return new a.Point(this.x,this.y)},getBottomRight:function(){return new a.Point(this.x+this.width,this.y+this.height).rotate(this.degrees,this.getTopLeft())},getTopRight:function(){return new a.Point(this.x+this.width,this.y).rotate(this.degrees,this.getTopLeft())},getBottomLeft:function(){return new a.Point(this.x,this.y+this.height).rotate(this.degrees,this.getTopLeft())},getCenter:function(){return new a.Point(this.x+this.width/2,this.y+this.height/2).rotate(this.degrees,this.getTopLeft())},getSize:function(){return new a.Point(this.width,this.height)},equals:function(b){return b instanceof a.Rect&&this.x===b.x&&this.y===b.y&&this.width===b.width&&this.height===b.height&&this.degrees===b.degrees},times:function(b){return new a.Rect(this.x*b,this.y*b,this.width*b,this.height*b,this.degrees)},translate:function(b){return new a.Rect(this.x+b.x,this.y+b.y,this.width,this.height,this.degrees)},union:function(b){var c=this.getBoundingBox();var d=b.getBoundingBox();var e=Math.min(c.x,d.x);var f=Math.min(c.y,d.y);var g=Math.max(c.x+c.width,d.x+d.width);var h=Math.max(c.y+c.height,d.y+d.height);return new a.Rect(e,f,g-e,h-f)},intersection:function(b){function c(b,c,e,f){var g=c.minus(b);var h=f.minus(e);var i=-h.x*g.y+g.x*h.y;if(0===i)return null;var j=(g.x*(b.y-e.y)-g.y*(b.x-e.x))/i;var k=(h.x*(b.y-e.y)-h.y*(b.x-e.x))/i;return-d<=j&&j<=1-d&&-d<=k&&k<=1-d?new a.Point(b.x+k*g.x,b.y+k*g.y):null}var d=1e-10;var e=[];var f=this.getTopLeft();b.containsPoint(f,d)&&e.push(f);var g=this.getTopRight();b.containsPoint(g,d)&&e.push(g);var h=this.getBottomLeft();b.containsPoint(h,d)&&e.push(h);var i=this.getBottomRight();b.containsPoint(i,d)&&e.push(i);var j=b.getTopLeft();this.containsPoint(j,d)&&e.push(j);var k=b.getTopRight();this.containsPoint(k,d)&&e.push(k);var l=b.getBottomLeft();this.containsPoint(l,d)&&e.push(l);var m=b.getBottomRight();this.containsPoint(m,d)&&e.push(m);var n=this._getSegments();var o=b._getSegments();for(var p=0;pv&&(v=z.x);z.yx&&(x=z.y)}return new a.Rect(u,w,v-u,x-w)},_getSegments:function(){var a=this.getTopLeft();var b=this.getTopRight();var c=this.getBottomLeft();var d=this.getBottomRight();return[[a,b],[b,d],[d,c],[c,a]]},rotate:function(b,c){b=a.positiveModulo(b,360);if(0===b)return this.clone();c=c||this.getCenter();var d=this.getTopLeft().rotate(b,c);var e=this.getTopRight().rotate(b,c);var f=e.minus(d);f=f.apply(function(a){var b=1e-15;return Math.abs(a)=-b&&(a.x-d.x)*f.x+(a.y-d.y)*f.y<=b&&(a.x-c.x)*g.x+(a.y-c.y)*g.y>=-b&&(a.x-e.x)*g.x+(a.y-e.y)*g.y<=b},toString:function(){return"["+Math.round(100*this.x)/100+", "+Math.round(100*this.y)/100+", "+Math.round(100*this.width)/100+"x"+Math.round(100*this.height)/100+", "+Math.round(100*this.degrees)/100+"deg]"}}}(OpenSeadragon);!function(a){function b(b){var c=Number(this.element.style.marginLeft.replace("px","")),e=Number(this.element.style.marginTop.replace("px","")),f=Number(this.element.style.width.replace("px","")),g=Number(this.element.style.height.replace("px","")),h=a.getElementSize(this.viewer.canvas);this.dragging=!0;if(this.element)if("horizontal"==this.scroll){if(-b.delta.x>0){if(c>-(f-h.x)){this.element.style.marginLeft=c+2*b.delta.x+"px";d(this,h.x,c+2*b.delta.x)}}else if(-b.delta.x<0&&c<0){this.element.style.marginLeft=c+2*b.delta.x+"px";d(this,h.x,c+2*b.delta.x)}}else if(-b.delta.y>0){if(e>-(g-h.y)){this.element.style.marginTop=e+2*b.delta.y+"px";d(this,h.y,e+2*b.delta.y)}}else if(-b.delta.y<0&&e<0){this.element.style.marginTop=e+2*b.delta.y+"px";d(this,h.y,e+2*b.delta.y)}return!1}function c(b){var c=Number(this.element.style.marginLeft.replace("px","")),e=Number(this.element.style.marginTop.replace("px","")),f=Number(this.element.style.width.replace("px","")),g=Number(this.element.style.height.replace("px","")),h=a.getElementSize(this.viewer.canvas);if(this.element)if("horizontal"==this.scroll){if(b.scroll>0){if(c>-(f-h.x)){this.element.style.marginLeft=c-60*b.scroll+"px";d(this,h.x,c-60*b.scroll)}}else if(b.scroll<0&&c<0){this.element.style.marginLeft=c-60*b.scroll+"px";d(this,h.x,c-60*b.scroll)}}else if(b.scroll<0){if(e>h.y-g){this.element.style.marginTop=e+60*b.scroll+"px";d(this,h.y,e+60*b.scroll)}}else if(b.scroll>0&&e<0){this.element.style.marginTop=e+60*b.scroll+"px";d(this,h.y,e+60*b.scroll)}return!1}function d(b,c,d){var e,f,g,h,i,j,k;e="horizontal"==b.scroll?b.panelWidth:b.panelHeight;f=Math.ceil(c/e)+5;g=Math.ceil((Math.abs(d)+c)/e)+1;f=g-f;f=f<0?0:f;for(j=f;jj+g.x-this.panelWidth){c=Math.min(c,h-g.x);this.element.style.marginLeft=-c+"px";d(this,g.x,-c)}else if(ck+g.y-this.panelHeight){c=Math.min(c,i-g.y);this.element.style.marginTop=-c+"px";d(this,g.y,-c)}else if(c1?c[1].springStiffness:5,animationTime:c.length>1?c[1].animationTime:1.5});a.console.assert("number"==typeof b.springStiffness&&0!==b.springStiffness,"[OpenSeadragon.Spring] options.springStiffness must be a non-zero number");a.console.assert("number"==typeof b.animationTime&&b.animationTime>=0,"[OpenSeadragon.Spring] options.animationTime must be a number greater than or equal to 0");if(b.exponential){this._exponential=!0;delete b.exponential}a.extend(!0,this,b);this.current={value:"number"==typeof this.initial?this.initial:this._exponential?0:1,time:a.now()};a.console.assert(!this._exponential||0!==this.current.value,"[OpenSeadragon.Spring] value must be non-zero for exponential springs");this.start={value:this.current.value,time:this.current.time};this.target={value:this.current.value,time:this.current.time};if(this._exponential){this.start._logValue=Math.log(this.start.value);this.target._logValue=Math.log(this.target.value);this.current._logValue=Math.log(this.current.value)}};a.Spring.prototype={resetTo:function(b){a.console.assert(!this._exponential||0!==b,"[OpenSeadragon.Spring.resetTo] target must be non-zero for exponential springs");this.start.value=this.target.value=this.current.value=b;this.start.time=this.target.time=this.current.time=a.now();if(this._exponential){this.start._logValue=Math.log(this.start.value);this.target._logValue=Math.log(this.target.value);this.current._logValue=Math.log(this.current.value)}},springTo:function(b){a.console.assert(!this._exponential||0!==b,"[OpenSeadragon.Spring.springTo] target must be non-zero for exponential springs");this.start.value=this.current.value;this.start.time=this.current.time;this.target.value=b;this.target.time=this.start.time+1e3*this.animationTime;if(this._exponential){this.start._logValue=Math.log(this.start.value);this.target._logValue=Math.log(this.target.value)}},shiftBy:function(b){this.start.value+=b;this.target.value+=b;if(this._exponential){a.console.assert(0!==this.target.value&&0!==this.start.value,"[OpenSeadragon.Spring.shiftBy] spring value must be non-zero for exponential springs");this.start._logValue=Math.log(this.start.value);this.target._logValue=Math.log(this.target.value)}},setExponential:function(b){this._exponential=b;if(this._exponential){a.console.assert(0!==this.current.value&&0!==this.target.value&&0!==this.start.value,"[OpenSeadragon.Spring.setExponential] spring value must be non-zero for exponential springs");this.start._logValue=Math.log(this.start.value);this.target._logValue=Math.log(this.target.value);this.current._logValue=Math.log(this.current.value)}},update:function(){this.current.time=a.now();var c,d;if(this._exponential){c=this.start._logValue;d=this.target._logValue}else{c=this.start.value;d=this.target.value}var e=this.current.time>=this.target.time?d:c+(d-c)*b(this.springStiffness,(this.current.time-this.start.time)/(this.target.time-this.start.time));var f=this.current.value;this._exponential?this.current.value=Math.exp(e):this.current.value=e;return f!=this.current.value},isAtTargetValue:function(){return this.current.value===this.target.value}}}(OpenSeadragon);!function(a){function b(b){a.extend(!0,this,{timeout:a.DEFAULT_SETTINGS.timeout,jobId:null},b);this.image=null}function c(a,b,c){var d;a.jobsInProgress--;if((!a.jobLimit||a.jobsInProgress0){d=a.jobQueue.shift();d.start();a.jobsInProgress++}c(b.image,b.errorMsg,b.request)}b.prototype={errorMsg:null,start:function(){var b=this;var c=this.abort;this.image=new Image;this.image.onload=function(){b.finish(!0)};this.image.onabort=this.image.onerror=function(){b.errorMsg="Image load aborted";b.finish(!1)};this.jobId=window.setTimeout(function(){b.errorMsg="Image load exceeded timeout";b.finish(!1)},this.timeout);if(this.loadWithAjax){this.request=a.makeAjaxRequest({url:this.src,withCredentials:this.ajaxWithCredentials,headers:this.ajaxHeaders,responseType:"arraybuffer",success:function(a){var c;try{c=new window.Blob([a.response])}catch(b){var d=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder;if("TypeError"===b.name&&d){var e=new d;e.append(a.response);c=e.getBlob()}}if(0===c.size){b.errorMsg="Empty image response.";b.finish(!1)}var f=(window.URL||window.webkitURL).createObjectURL(c);b.image.src=f},error:function(a){b.errorMsg="Image load aborted - XHR error";b.finish(!1)}});this.abort=function(){b.request.abort();"function"==typeof c&&c()}}else{this.crossOriginPolicy!==!1&&(this.image.crossOrigin=this.crossOriginPolicy);this.image.src=this.src}},finish:function(a){this.image.onload=this.image.onerror=this.image.onabort=null;a||(this.image=null);this.jobId&&window.clearTimeout(this.jobId);this.callback(this)}};a.ImageLoader=function(b){a.extend(!0,this,{jobLimit:a.DEFAULT_SETTINGS.imageLoaderLimit,timeout:a.DEFAULT_SETTINGS.timeout,jobQueue:[],jobsInProgress:0},b)};a.ImageLoader.prototype={addJob:function(a){var d=this,e=function(b){c(d,b,a.callback)},f={src:a.src,loadWithAjax:a.loadWithAjax,ajaxHeaders:a.loadWithAjax?a.ajaxHeaders:null,crossOriginPolicy:a.crossOriginPolicy,ajaxWithCredentials:a.ajaxWithCredentials,callback:e,abort:a.abort,timeout:this.timeout},g=new b(f);if(!this.jobLimit||this.jobsInProgressc&&(c=e)}return c},needsUpdate:function(){a.console.error("[Drawer.needsUpdate] this function is deprecated. Use World.needsDraw instead.");return this.viewer.world.needsDraw()},numTilesLoaded:function(){a.console.error("[Drawer.numTilesLoaded] this function is deprecated. Use TileCache.numTilesLoaded instead.");return this.viewer.tileCache.numTilesLoaded()},reset:function(){a.console.error("[Drawer.reset] this function is deprecated. Use World.resetItems instead.");this.viewer.world.resetItems();return this},update:function(){a.console.error("[Drawer.update] this function is deprecated. Use Drawer.clear and World.draw instead.");this.clear();this.viewer.world.draw();return this},canRotate:function(){return this.useCanvas},destroy:function(){this.canvas.width=1;this.canvas.height=1;this.sketchCanvas=null;this.sketchContext=null},clear:function(){this.canvas.innerHTML="";if(this.useCanvas){var a=this._calculateCanvasSize();if(this.canvas.width!=a.x||this.canvas.height!=a.y){this.canvas.width=a.x;this.canvas.height=a.y;if(null!==this.sketchCanvas){var b=this._calculateSketchCanvasSize();this.sketchCanvas.width=b.x;this.sketchCanvas.height=b.y}}this._clear()}},_clear:function(a,b){if(this.useCanvas){var c=this._getContext(a);if(b)c.clearRect(b.x,b.y,b.width,b.height);else{var d=c.canvas;c.clearRect(0,0,d.width,d.height)}}},viewportToDrawerRectangle:function(b){var c=this.viewport.pixelFromPointNoRotate(b.getTopLeft(),!0);var d=this.viewport.deltaPixelsFromPointsNoRotate(b.getSize(),!0);return new a.Rect(c.x*a.pixelDensityRatio,c.y*a.pixelDensityRatio,d.x*a.pixelDensityRatio,d.y*a.pixelDensityRatio)},drawTile:function(b,c,d,e,f){a.console.assert(b,"[Drawer.drawTile] tile is required");a.console.assert(c,"[Drawer.drawTile] drawingHandler is required");if(this.useCanvas){var g=this._getContext(d);e=e||1;b.drawCanvas(g,c,e,f)}else b.drawHTML(this.canvas)},_getContext:function(a){var b=this.context;if(a){if(null===this.sketchCanvas){this.sketchCanvas=document.createElement("canvas");var c=this._calculateSketchCanvasSize();this.sketchCanvas.width=c.x;this.sketchCanvas.height=c.y;this.sketchContext=this.sketchCanvas.getContext("2d");if(0===this.viewport.getRotation()){var d=this;this.viewer.addHandler("rotate",function a(){if(0!==d.viewport.getRotation()){d.viewer.removeHandler("rotate",a);var b=d._calculateSketchCanvasSize();d.sketchCanvas.width=b.x;d.sketchCanvas.height=b.y}})}}b=this.sketchContext}return b},saveContext:function(a){this.useCanvas&&this._getContext(a).save()},restoreContext:function(a){this.useCanvas&&this._getContext(a).restore()},setClip:function(a,b){if(this.useCanvas){var c=this._getContext(b);c.beginPath();c.rect(a.x,a.y,a.width,a.height);c.clip()}},drawRectangle:function(a,b,c){if(this.useCanvas){var d=this._getContext(c);d.save();d.fillStyle=b;d.fillRect(a.x,a.y,a.width,a.height);d.restore()}},blendSketch:function(b,c,d,e){var f=b;a.isPlainObject(f)||(f={opacity:b,scale:c,translate:d,compositeOperation:e});if(this.useCanvas&&this.sketchCanvas){b=f.opacity;e=f.compositeOperation;var g=f.bounds;this.context.save();this.context.globalAlpha=b;e&&(this.context.globalCompositeOperation=e);if(g){if(g.x<0){g.width+=g.x;g.x=0}g.x+g.width>this.canvas.width&&(g.width=this.canvas.width-g.x);if(g.y<0){g.height+=g.y;g.y=0}g.y+g.height>this.canvas.height&&(g.height=this.canvas.height-g.y);this.context.drawImage(this.sketchCanvas,g.x,g.y,g.width,g.height,g.x,g.y,g.width,g.height)}else{c=f.scale||1;d=f.translate;var h=d instanceof a.Point?d:new a.Point(0,0);var i=0;var j=0;if(d){var k=this.sketchCanvas.width-this.canvas.width;var l=this.sketchCanvas.height-this.canvas.height;i=Math.round(k/2);j=Math.round(l/2)}this.context.drawImage(this.sketchCanvas,h.x-i*c,h.y-j*c,(this.canvas.width+2*i)*c,(this.canvas.height+2*j)*c,-i,-j,this.canvas.width+2*i,this.canvas.height+2*j)}this.context.restore()}},drawDebugInfo:function(b,c,d,e){if(this.useCanvas){var f=this.viewer.world.getIndexOfItem(e)%this.debugGridColor.length;var g=this.context;g.save();g.lineWidth=2*a.pixelDensityRatio;g.font="small-caps bold "+13*a.pixelDensityRatio+"px arial";g.strokeStyle=this.debugGridColor[f];g.fillStyle=this.debugGridColor[f];0!==this.viewport.degrees&&this._offsetForRotation({degrees:this.viewport.degrees});e.getRotation(!0)%360!==0&&this._offsetForRotation({degrees:e.getRotation(!0),point:e.viewport.pixelFromPointNoRotate(e._getRotationPoint(!0),!0)});g.strokeRect(b.position.x*a.pixelDensityRatio,b.position.y*a.pixelDensityRatio,b.size.x*a.pixelDensityRatio,b.size.y*a.pixelDensityRatio);var h=(b.position.x+b.size.x/2)*a.pixelDensityRatio;var i=(b.position.y+b.size.y/2)*a.pixelDensityRatio;g.translate(h,i);g.rotate(Math.PI/180*-this.viewport.degrees);g.translate(-h,-i);if(0===b.x&&0===b.y){g.fillText("Zoom: "+this.viewport.getZoom(),b.position.x*a.pixelDensityRatio,(b.position.y-30)*a.pixelDensityRatio);g.fillText("Pan: "+this.viewport.getBounds().toString(),b.position.x*a.pixelDensityRatio,(b.position.y-20)*a.pixelDensityRatio)}g.fillText("Level: "+b.level,(b.position.x+10)*a.pixelDensityRatio,(b.position.y+20)*a.pixelDensityRatio);g.fillText("Column: "+b.x,(b.position.x+10)*a.pixelDensityRatio,(b.position.y+30)*a.pixelDensityRatio);g.fillText("Row: "+b.y,(b.position.x+10)*a.pixelDensityRatio,(b.position.y+40)*a.pixelDensityRatio);g.fillText("Order: "+d+" of "+c,(b.position.x+10)*a.pixelDensityRatio,(b.position.y+50)*a.pixelDensityRatio);g.fillText("Size: "+b.size.toString(),(b.position.x+10)*a.pixelDensityRatio,(b.position.y+60)*a.pixelDensityRatio);g.fillText("Position: "+b.position.toString(),(b.position.x+10)*a.pixelDensityRatio,(b.position.y+70)*a.pixelDensityRatio);0!==this.viewport.degrees&&this._restoreRotationChanges();e.getRotation(!0)%360!==0&&this._restoreRotationChanges();g.restore()}},debugRect:function(b){if(this.useCanvas){var c=this.context;c.save();c.lineWidth=2*a.pixelDensityRatio;c.strokeStyle=this.debugGridColor[0];c.fillStyle=this.debugGridColor[0];c.strokeRect(b.x*a.pixelDensityRatio,b.y*a.pixelDensityRatio,b.width*a.pixelDensityRatio,b.height*a.pixelDensityRatio);c.restore()}},getCanvasSize:function(b){var c=this._getContext(b).canvas;return new a.Point(c.width,c.height)},getCanvasCenter:function(){return new a.Point(this.canvas.width/2,this.canvas.height/2)},_offsetForRotation:function(b){var c=b.point?b.point.times(a.pixelDensityRatio):this.getCanvasCenter();var d=this._getContext(b.useSketch);d.save();d.translate(c.x,c.y);d.rotate(Math.PI/180*b.degrees);d.translate(-c.x,-c.y)},_restoreRotationChanges:function(a){var b=this._getContext(a);b.restore()},_calculateCanvasSize:function(){var b=a.pixelDensityRatio;var c=this.viewport.getContainerSize();return{x:c.x*b,y:c.y*b}},_calculateSketchCanvasSize:function(){var a=this._calculateCanvasSize();if(0===this.viewport.getRotation())return a;var b=Math.ceil(Math.sqrt(a.x*a.x+a.y*a.y));return{x:b,y:b}}}}(OpenSeadragon);!function(a){a.Viewport=function(b){var c=arguments;c.length&&c[0]instanceof a.Point&&(b={containerSize:c[0],contentSize:c[1],config:c[2]});if(b.config){a.extend(!0,b,b.config);delete b.config}this._margins=a.extend({left:0,top:0,right:0,bottom:0},b.margins||{});delete b.margins;a.extend(!0,this,{containerSize:null,contentSize:null,zoomPoint:null,viewer:null,springStiffness:a.DEFAULT_SETTINGS.springStiffness,animationTime:a.DEFAULT_SETTINGS.animationTime,minZoomImageRatio:a.DEFAULT_SETTINGS.minZoomImageRatio,maxZoomPixelRatio:a.DEFAULT_SETTINGS.maxZoomPixelRatio,visibilityRatio:a.DEFAULT_SETTINGS.visibilityRatio,wrapHorizontal:a.DEFAULT_SETTINGS.wrapHorizontal,wrapVertical:a.DEFAULT_SETTINGS.wrapVertical,defaultZoomLevel:a.DEFAULT_SETTINGS.defaultZoomLevel,minZoomLevel:a.DEFAULT_SETTINGS.minZoomLevel,maxZoomLevel:a.DEFAULT_SETTINGS.maxZoomLevel,degrees:a.DEFAULT_SETTINGS.degrees,homeFillsViewer:a.DEFAULT_SETTINGS.homeFillsViewer},b);this._updateContainerInnerSize();this.centerSpringX=new a.Spring({initial:0,springStiffness:this.springStiffness,animationTime:this.animationTime});this.centerSpringY=new a.Spring({initial:0,springStiffness:this.springStiffness,animationTime:this.animationTime});this.zoomSpring=new a.Spring({exponential:!0,initial:1,springStiffness:this.springStiffness,animationTime:this.animationTime});this._oldCenterX=this.centerSpringX.current.value;this._oldCenterY=this.centerSpringY.current.value;this._oldZoom=this.zoomSpring.current.value;this._setContentBounds(new a.Rect(0,0,1,1),1);this.goHome(!0);this.update()};a.Viewport.prototype={resetContentSize:function(b){a.console.assert(b,"[Viewport.resetContentSize] contentSize is required");a.console.assert(b instanceof a.Point,"[Viewport.resetContentSize] contentSize must be an OpenSeadragon.Point");a.console.assert(b.x>0,"[Viewport.resetContentSize] contentSize.x must be greater than 0");a.console.assert(b.y>0,"[Viewport.resetContentSize] contentSize.y must be greater than 0");this._setContentBounds(new a.Rect(0,0,1,b.y/b.x),b.x);return this},setHomeBounds:function(b,c){a.console.error("[Viewport.setHomeBounds] this function is deprecated; The content bounds should not be set manually.");this._setContentBounds(b,c)},_setContentBounds:function(b,c){a.console.assert(b,"[Viewport._setContentBounds] bounds is required");a.console.assert(b instanceof a.Rect,"[Viewport._setContentBounds] bounds must be an OpenSeadragon.Rect");a.console.assert(b.width>0,"[Viewport._setContentBounds] bounds.width must be greater than 0");a.console.assert(b.height>0,"[Viewport._setContentBounds] bounds.height must be greater than 0");this._contentBoundsNoRotate=b.clone();this._contentSizeNoRotate=this._contentBoundsNoRotate.getSize().times(c);this._contentBounds=b.rotate(this.degrees).getBoundingBox();this._contentSize=this._contentBounds.getSize().times(c);this._contentAspectRatio=this._contentSize.x/this._contentSize.y;this.viewer&&this.viewer.raiseEvent("reset-size",{contentSize:this._contentSizeNoRotate.clone(),contentFactor:c,homeBounds:this._contentBoundsNoRotate.clone(),contentBounds:this._contentBounds.clone()})},getHomeZoom:function(){if(this.defaultZoomLevel)return this.defaultZoomLevel;var a=this._contentAspectRatio/this.getAspectRatio();var b;b=this.homeFillsViewer?a>=1?a:1:a>=1?1:a;return b/this._contentBounds.width},getHomeBounds:function(){return this.getHomeBoundsNoRotate().rotate(-this.getRotation())},getHomeBoundsNoRotate:function(){var b=this._contentBounds.getCenter();var c=1/this.getHomeZoom();var d=c/this.getAspectRatio();return new a.Rect(b.x-c/2,b.y-d/2,c,d)},goHome:function(a){this.viewer&&this.viewer.raiseEvent("home",{immediately:a});return this.fitBounds(this.getHomeBounds(),a)},getMinZoom:function(){var a=this.getHomeZoom(),b=this.minZoomLevel?this.minZoomLevel:this.minZoomImageRatio*a;return b},getMaxZoom:function(){var a=this.maxZoomLevel;if(!a){a=this._contentSize.x*this.maxZoomPixelRatio/this._containerInnerSize.x;a/=this._contentBounds.width}return Math.max(a,this.getHomeZoom())},getAspectRatio:function(){return this._containerInnerSize.x/this._containerInnerSize.y},getContainerSize:function(){return new a.Point(this.containerSize.x,this.containerSize.y)},getMargins:function(){return a.extend({},this._margins)},setMargins:function(b){a.console.assert("object"===a.type(b),"[Viewport.setMargins] margins must be an object");this._margins=a.extend({left:0,top:0,right:0,bottom:0},b);this._updateContainerInnerSize();this.viewer&&this.viewer.forceRedraw()},getBounds:function(a){return this.getBoundsNoRotate(a).rotate(-this.getRotation())},getBoundsNoRotate:function(b){var c=this.getCenter(b);var d=1/this.getZoom(b);var e=d/this.getAspectRatio();return new a.Rect(c.x-d/2,c.y-e/2,d,e)},getBoundsWithMargins:function(a){return this.getBoundsNoRotateWithMargins(a).rotate(-this.getRotation(),this.getCenter(a))},getBoundsNoRotateWithMargins:function(a){var b=this.getBoundsNoRotate(a);var c=this._containerInnerSize.x*this.getZoom(a);b.x-=this._margins.left/c;b.y-=this._margins.top/c;b.width+=(this._margins.left+this._margins.right)/c;b.height+=(this._margins.top+this._margins.bottom)/c;return b},getCenter:function(b){var c,d,e,f,g,h,i,j,k=new a.Point(this.centerSpringX.current.value,this.centerSpringY.current.value),l=new a.Point(this.centerSpringX.target.value,this.centerSpringY.target.value);if(b)return k;if(!this.zoomPoint)return l;c=this.pixelFromPoint(this.zoomPoint,!0);d=this.getZoom();e=1/d;f=e/this.getAspectRatio();g=new a.Rect(k.x-e/2,k.y-f/2,e,f);h=this._pixelFromPoint(this.zoomPoint,g);i=h.minus(c);j=i.divide(this._containerInnerSize.x*d);return l.plus(j)},getZoom:function(a){return a?this.zoomSpring.current.value:this.zoomSpring.target.value},_applyZoomConstraints:function(a){return Math.max(Math.min(a,this.getMaxZoom()),this.getMinZoom())},_applyBoundaryConstraints:function(b){var c=new a.Rect(b.x,b.y,b.width,b.height);if(this.wrapHorizontal);else{var d=this.visibilityRatio*c.width;var e=c.x+c.width;var f=this._contentBoundsNoRotate.x+this._contentBoundsNoRotate.width;var g=this._contentBoundsNoRotate.x-e+d;var h=f-c.x-d;d>this._contentBoundsNoRotate.width?c.x+=(g+h)/2:h<0?c.x+=h:g>0&&(c.x+=g)}if(this.wrapVertical);else{var i=this.visibilityRatio*c.height;var j=c.y+c.height;var k=this._contentBoundsNoRotate.y+this._contentBoundsNoRotate.height;var l=this._contentBoundsNoRotate.y-j+i;var m=k-c.y-i;i>this._contentBoundsNoRotate.height?c.y+=(l+m)/2:m<0?c.y+=m:l>0&&(c.y+=l)}return c},_raiseConstraintsEvent:function(a){this.viewer&&this.viewer.raiseEvent("constrain",{immediately:a})},applyConstraints:function(a){var b=this.getZoom();var c=this._applyZoomConstraints(b);b!==c&&this.zoomTo(c,this.zoomPoint,a);var d=this.getBoundsNoRotate();var e=this._applyBoundaryConstraints(d);this._raiseConstraintsEvent(a);(d.x!==e.x||d.y!==e.y||a)&&this.fitBounds(e.rotate(-this.getRotation()),a);return this},ensureVisible:function(a){return this.applyConstraints(a)},_fitBounds:function(b,c){c=c||{};var d=c.immediately||!1;var e=c.constraints||!1;var f=this.getAspectRatio();var g=b.getCenter();var h=new a.Rect(b.x,b.y,b.width,b.height,b.degrees+this.getRotation()).getBoundingBox();h.getAspectRatio()>=f?h.height=h.width/f:h.width=h.height*f;h.x=g.x-h.width/2;h.y=g.y-h.height/2;var i=1/h.width;if(e){var j=h.getAspectRatio();var k=this._applyZoomConstraints(i);if(i!==k){i=k;h.width=1/i;h.x=g.x-h.width/2;h.height=h.width/j;h.y=g.y-h.height/2}h=this._applyBoundaryConstraints(h);g=h.getCenter();this._raiseConstraintsEvent(d)}if(d){this.panTo(g,!0);return this.zoomTo(i,null,!0)}this.panTo(this.getCenter(!0),!0);this.zoomTo(this.getZoom(!0),null,!0);var l=this.getBounds();var m=this.getZoom();if(0===m||Math.abs(i/m-1)<1e-8){this.zoomTo(i,!0);return this.panTo(g,d)}h=h.rotate(-this.getRotation());var n=h.getTopLeft().times(i).minus(l.getTopLeft().times(m)).divide(i-m);return this.zoomTo(i,n,d)},fitBounds:function(a,b){return this._fitBounds(a,{immediately:b,constraints:!1})},fitBoundsWithConstraints:function(a,b){return this._fitBounds(a,{immediately:b,constraints:!0})},fitVertically:function(b){var c=new a.Rect(this._contentBounds.x+this._contentBounds.width/2,this._contentBounds.y,0,this._contentBounds.height);return this.fitBounds(c,b)},fitHorizontally:function(b){var c=new a.Rect(this._contentBounds.x,this._contentBounds.y+this._contentBounds.height/2,this._contentBounds.width,0);return this.fitBounds(c,b)},getConstrainedBounds:function(a){var b,c;b=this.getBounds(a);c=this._applyBoundaryConstraints(b);return c},panBy:function(b,c){var d=new a.Point(this.centerSpringX.target.value,this.centerSpringY.target.value);return this.panTo(d.plus(b),c)},panTo:function(a,b){if(b){this.centerSpringX.resetTo(a.x);this.centerSpringY.resetTo(a.y)}else{this.centerSpringX.springTo(a.x);this.centerSpringY.springTo(a.y)}this.viewer&&this.viewer.raiseEvent("pan",{center:a,immediately:b});return this},zoomBy:function(a,b,c){return this.zoomTo(this.zoomSpring.target.value*a,b,c)},zoomTo:function(b,c,d){var e=this;this.zoomPoint=c instanceof a.Point&&!isNaN(c.x)&&!isNaN(c.y)?c:null;d?this._adjustCenterSpringsForZoomPoint(function(){e.zoomSpring.resetTo(b)}):this.zoomSpring.springTo(b);this.viewer&&this.viewer.raiseEvent("zoom",{zoom:b,refPoint:c,immediately:d});return this},setRotation:function(b){if(!this.viewer||!this.viewer.drawer.canRotate())return this;this.degrees=a.positiveModulo(b,360);this._setContentBounds(this.viewer.world.getHomeBounds(),this.viewer.world.getContentFactor());this.viewer.forceRedraw();this.viewer.raiseEvent("rotate",{degrees:b});return this},getRotation:function(){return this.degrees},resize:function(a,b){var c,d=this.getBoundsNoRotate(),e=d;this.containerSize.x=a.x;this.containerSize.y=a.y;this._updateContainerInnerSize();if(b){c=a.x/this.containerSize.x;e.width=d.width*c;e.height=e.width/this.getAspectRatio()}this.viewer&&this.viewer.raiseEvent("resize",{newContainerSize:a,maintain:b});return this.fitBounds(e,!0)},_updateContainerInnerSize:function(){this._containerInnerSize=new a.Point(Math.max(1,this.containerSize.x-(this._margins.left+this._margins.right)),Math.max(1,this.containerSize.y-(this._margins.top+this._margins.bottom)))},update:function(){var a=this;this._adjustCenterSpringsForZoomPoint(function(){a.zoomSpring.update()});this.centerSpringX.update();this.centerSpringY.update();var b=this.centerSpringX.current.value!==this._oldCenterX||this.centerSpringY.current.value!==this._oldCenterY||this.zoomSpring.current.value!==this._oldZoom;this._oldCenterX=this.centerSpringX.current.value;this._oldCenterY=this.centerSpringY.current.value;this._oldZoom=this.zoomSpring.current.value;return b},_adjustCenterSpringsForZoomPoint:function(a){if(this.zoomPoint){var b=this.pixelFromPoint(this.zoomPoint,!0);a();var c=this.pixelFromPoint(this.zoomPoint,!0);var d=c.minus(b);var e=this.deltaPointsFromPixels(d,!0);this.centerSpringX.shiftBy(e.x);this.centerSpringY.shiftBy(e.y);this.zoomSpring.isAtTargetValue()&&(this.zoomPoint=null)}else a()},deltaPixelsFromPointsNoRotate:function(a,b){return a.times(this._containerInnerSize.x*this.getZoom(b))},deltaPixelsFromPoints:function(a,b){return this.deltaPixelsFromPointsNoRotate(a.rotate(this.getRotation()),b)},deltaPointsFromPixelsNoRotate:function(a,b){return a.divide(this._containerInnerSize.x*this.getZoom(b))},deltaPointsFromPixels:function(a,b){return this.deltaPointsFromPixelsNoRotate(a,b).rotate(-this.getRotation())},pixelFromPointNoRotate:function(a,b){return this._pixelFromPointNoRotate(a,this.getBoundsNoRotate(b))},pixelFromPoint:function(a,b){return this._pixelFromPoint(a,this.getBoundsNoRotate(b))},_pixelFromPointNoRotate:function(b,c){return b.minus(c.getTopLeft()).times(this._containerInnerSize.x/c.width).plus(new a.Point(this._margins.left,this._margins.top))},_pixelFromPoint:function(a,b){return this._pixelFromPointNoRotate(a.rotate(this.getRotation(),this.getCenter(!0)),b)},pointFromPixelNoRotate:function(b,c){var d=this.getBoundsNoRotate(c);return b.minus(new a.Point(this._margins.left,this._margins.top)).divide(this._containerInnerSize.x/d.width).plus(d.getTopLeft())},pointFromPixel:function(a,b){return this.pointFromPixelNoRotate(a,b).rotate(-this.getRotation(),this.getCenter(!0))},_viewportToImageDelta:function(b,c){var d=this._contentBoundsNoRotate.width;return new a.Point(b*this._contentSizeNoRotate.x/d,c*this._contentSizeNoRotate.x/d)},viewportToImageCoordinates:function(b,c){if(b instanceof a.Point)return this.viewportToImageCoordinates(b.x,b.y);if(this.viewer){var d=this.viewer.world.getItemCount();if(d>1)a.console.error("[Viewport.viewportToImageCoordinates] is not accurate with multi-image; use TiledImage.viewportToImageCoordinates instead.");else if(1===d){var e=this.viewer.world.getItemAt(0);return e.viewportToImageCoordinates(b,c,!0)}}return this._viewportToImageDelta(b-this._contentBoundsNoRotate.x,c-this._contentBoundsNoRotate.y)},_imageToViewportDelta:function(b,c){var d=this._contentBoundsNoRotate.width;return new a.Point(b/this._contentSizeNoRotate.x*d,c/this._contentSizeNoRotate.x*d)},imageToViewportCoordinates:function(b,c){if(b instanceof a.Point)return this.imageToViewportCoordinates(b.x,b.y);if(this.viewer){var d=this.viewer.world.getItemCount();if(d>1)a.console.error("[Viewport.imageToViewportCoordinates] is not accurate with multi-image; use TiledImage.imageToViewportCoordinates instead.");else if(1===d){var e=this.viewer.world.getItemAt(0);return e.imageToViewportCoordinates(b,c,!0)}}var f=this._imageToViewportDelta(b,c);f.x+=this._contentBoundsNoRotate.x;f.y+=this._contentBoundsNoRotate.y;return f},imageToViewportRectangle:function(b,c,d,e){var f=b;f instanceof a.Rect||(f=new a.Rect(b,c,d,e));if(this.viewer){var g=this.viewer.world.getItemCount();if(g>1)a.console.error("[Viewport.imageToViewportRectangle] is not accurate with multi-image; use TiledImage.imageToViewportRectangle instead.");else if(1===g){var h=this.viewer.world.getItemAt(0);return h.imageToViewportRectangle(b,c,d,e,!0)}}var i=this.imageToViewportCoordinates(f.x,f.y);var j=this._imageToViewportDelta(f.width,f.height);return new a.Rect(i.x,i.y,j.x,j.y,f.degrees)},viewportToImageRectangle:function(b,c,d,e){var f=b;f instanceof a.Rect||(f=new a.Rect(b,c,d,e));if(this.viewer){var g=this.viewer.world.getItemCount();if(g>1)a.console.error("[Viewport.viewportToImageRectangle] is not accurate with multi-image; use TiledImage.viewportToImageRectangle instead.");else if(1===g){var h=this.viewer.world.getItemAt(0);return h.viewportToImageRectangle(b,c,d,e,!0)}}var i=this.viewportToImageCoordinates(f.x,f.y);var j=this._viewportToImageDelta(f.width,f.height);return new a.Rect(i.x,i.y,j.x,j.y,f.degrees)},viewerElementToImageCoordinates:function(a){var b=this.pointFromPixel(a,!0);return this.viewportToImageCoordinates(b)},imageToViewerElementCoordinates:function(a){var b=this.imageToViewportCoordinates(a);return this.pixelFromPoint(b,!0)},windowToImageCoordinates:function(b){a.console.assert(this.viewer,"[Viewport.windowToImageCoordinates] the viewport must have a viewer.");var c=b.minus(a.getElementPosition(this.viewer.element));return this.viewerElementToImageCoordinates(c)},imageToWindowCoordinates:function(b){a.console.assert(this.viewer,"[Viewport.imageToWindowCoordinates] the viewport must have a viewer.");var c=this.imageToViewerElementCoordinates(b);return c.plus(a.getElementPosition(this.viewer.element))},viewerElementToViewportCoordinates:function(a){return this.pointFromPixel(a,!0)},viewportToViewerElementCoordinates:function(a){return this.pixelFromPoint(a,!0)},viewerElementToViewportRectangle:function(b){return a.Rect.fromSummits(this.pointFromPixel(b.getTopLeft(),!0),this.pointFromPixel(b.getTopRight(),!0),this.pointFromPixel(b.getBottomLeft(),!0))},viewportToViewerElementRectangle:function(b){return a.Rect.fromSummits(this.pixelFromPoint(b.getTopLeft(),!0),this.pixelFromPoint(b.getTopRight(),!0),this.pixelFromPoint(b.getBottomLeft(),!0))},windowToViewportCoordinates:function(b){a.console.assert(this.viewer,"[Viewport.windowToViewportCoordinates] the viewport must have a viewer.");var c=b.minus(a.getElementPosition(this.viewer.element));return this.viewerElementToViewportCoordinates(c)},viewportToWindowCoordinates:function(b){a.console.assert(this.viewer,"[Viewport.viewportToWindowCoordinates] the viewport must have a viewer.");var c=this.viewportToViewerElementCoordinates(b);return c.plus(a.getElementPosition(this.viewer.element))},viewportToImageZoom:function(b){if(this.viewer){var c=this.viewer.world.getItemCount();if(c>1)a.console.error("[Viewport.viewportToImageZoom] is not accurate with multi-image.");else if(1===c){var d=this.viewer.world.getItemAt(0);return d.viewportToImageZoom(b)}}var e=this._contentSizeNoRotate.x;var f=this._containerInnerSize.x;var g=this._contentBoundsNoRotate.width;var h=f/e*g;return b*h},imageToViewportZoom:function(b){if(this.viewer){var c=this.viewer.world.getItemCount();if(c>1)a.console.error("[Viewport.imageToViewportZoom] is not accurate with multi-image.");else if(1===c){var d=this.viewer.world.getItemAt(0);return d.imageToViewportZoom(b)}}var e=this._contentSizeNoRotate.x;var f=this._containerInnerSize.x;var g=this._contentBoundsNoRotate.width;var h=e/f/g;return b*h}}}(OpenSeadragon);!function(a){function b(a,b,d,e,f,g,h,i,j){var k=h.getBoundingBox().getTopLeft();var l=h.getBoundingBox().getBottomRight();a.viewer&&a.viewer.raiseEvent("update-level",{tiledImage:a,havedrawn:b,level:e,opacity:f,visibility:g,drawArea:h,topleft:k,bottomright:l,currenttime:i,best:j});m(a.coverage,e);m(a.loadingCoverage,e);var n=a._getCornerTiles(e,k,l);var o=n.topLeft;var p=n.bottomRight;var q=a.source.getNumTiles(e);var r=a.viewport.pixelFromPoint(a.viewport.getCenter());for(var s=o.x;s<=p.x;s++)for(var t=o.y;t<=p.y;t++){if(!a.wrapHorizontal&&!a.wrapVertical){var u=a.source.getTileBounds(e,s,t);if(null===h.intersection(u))continue}j=c(a,d,b,s,t,e,f,g,r,q,i,j)}return j}function c(a,b,c,e,f,j,m,o,p,q,r,s){var t=d(e,f,j,a,a.source,a.tilesMatrix,r,q,a._worldWidthCurrent,a._worldHeightCurrent),u=c;a.viewer&&a.viewer.raiseEvent("update-tile",{tiledImage:a,tile:t});l(a.coverage,j,e,f,!1);var v=t.loaded||t.loading||k(a.loadingCoverage,j,e,f);l(a.loadingCoverage,j,e,f,v);if(!t.exists)return s;b&&!u&&(k(a.coverage,j,e,f)?l(a.coverage,j,e,f,!0):u=!0);if(!u)return s;h(t,a.source.tileOverlap,a.viewport,p,o,a);if(!t.loaded)if(t.context2D)g(a,t);else{var w=a._tileCache.getImageRecord(t.cacheKey);if(w){var x=w.getImage();g(a,t,x)}}if(t.loaded){var y=i(a,t,e,f,j,m,r);y&&(a._needsDraw=!0)}else t.loading?a._tilesLoading++:v||(s=n(s,t));return s}function d(b,c,d,e,f,g,h,i,j,k){var l,m,n,o,p,q,r,s;g[d]||(g[d]={});g[d][b]||(g[d][b]={});if(!g[d][b][c]){l=(i.x+b%i.x)%i.x;m=(i.y+c%i.y)%i.y;n=f.getTileBounds(d,l,m);o=f.tileExists(d,l,m);p=f.getTileUrl(d,l,m);if(e.loadTilesWithAjax){q=f.getTileAjaxHeaders(d,l,m);a.isPlainObject(e.ajaxHeaders)&&(q=a.extend({},e.ajaxHeaders,q))}else q=null;r=f.getContext2D?f.getContext2D(d,l,m):void 0;n.x+=(b-l)/i.x;n.y+=k/j*((c-m)/i.y);s=new a.Tile(d,b,c,n,o,p,r,e.loadTilesWithAjax,q);l===i.x-1&&(s.isRightMost=!0);m===i.y-1&&(s.isBottomMost=!0);g[d][b][c]=s}s=g[d][b][c];s.lastTouchTime=h;return s}function e(a,b,c){b.loading=!0;a._imageLoader.addJob({src:b.url,loadWithAjax:b.loadWithAjax,ajaxHeaders:b.ajaxHeaders,crossOriginPolicy:a.crossOriginPolicy,ajaxWithCredentials:a.ajaxWithCredentials,callback:function(d,e,g){f(a,b,c,d,e,g)},abort:function(){b.loading=!1}})}function f(b,c,d,e,f,h){if(e)if(da.visibility?b:b.visibility==a.visibility&&b.squaredDistance1&&i>b.smoothTileEdgesMinZoom&&!b.iOSDevice&&b.getRotation(!0)%360===0&&a.supportsCanvas){e=!0;f=d.getScaleForEdgeSmoothing();g=d.getTranslationForEdgeSmoothing(f,b._drawer.getCanvasSize(!1),b._drawer.getCanvasSize(!0))}var j;if(e){f||(j=b.viewport.viewportToViewerElementRectangle(b.getClippedBounds(!0)).getIntegerBoundingBox().times(a.pixelDensityRatio));b._drawer._clear(!0,j)}if(!f){0!==b.viewport.degrees&&b._drawer._offsetForRotation({degrees:b.viewport.degrees,useSketch:e});b.getRotation(!0)%360!==0&&b._drawer._offsetForRotation({degrees:b.getRotation(!0),point:b.viewport.pixelFromPointNoRotate(b._getRotationPoint(!0),!0),useSketch:e})}var k=!1;if(b._clip){b._drawer.saveContext(e);var l=b.imageToViewportRectangle(b._clip,!0);l=l.rotate(-b.getRotation(!0),b._getRotationPoint(!0));var m=b._drawer.viewportToDrawerRectangle(l);f&&(m=m.times(f));g&&(m=m.translate(g));b._drawer.setClip(m,e);k=!0}if(b.placeholderFillStyle&&b._hasOpaqueTile===!1){var n=b._drawer.viewportToDrawerRectangle(b.getBounds(!0));f&&(n=n.times(f));g&&(n=n.translate(g));var o=null;o="function"==typeof b.placeholderFillStyle?b.placeholderFillStyle(b,b._drawer.context):b.placeholderFillStyle;b._drawer.drawRectangle(n,o,e)}for(var q=c.length-1;q>=0;q--){d=c[q];b._drawer.drawTile(d,b._drawingHandler,e,f,g);d.beingDrawn=!0;b.viewer&&b.viewer.raiseEvent("tile-drawn",{tiledImage:b,tile:d})}k&&b._drawer.restoreContext(e);if(!f){b.getRotation(!0)%360!==0&&b._drawer._restoreRotationChanges(e);0!==b.viewport.degrees&&b._drawer._restoreRotationChanges(e)}if(e){if(f){0!==b.viewport.degrees&&b._drawer._offsetForRotation({degrees:b.viewport.degrees,useSketch:!1});b.getRotation(!0)%360!==0&&b._drawer._offsetForRotation({degrees:b.getRotation(!0),point:b.viewport.pixelFromPointNoRotate(b._getRotationPoint(!0),!0),useSketch:!1})}b._drawer.blendSketch({opacity:b.opacity,scale:f,translate:g,compositeOperation:b.compositeOperation,bounds:j});if(f){b.getRotation(!0)%360!==0&&b._drawer._restoreRotationChanges(!1);0!==b.viewport.degrees&&b._drawer._restoreRotationChanges(!1)}}p(b,c)}}function p(b,c){if(b.debugMode)for(var d=c.length-1;d>=0;d--){var e=c[d];try{b._drawer.drawDebugInfo(e,c.length,d,b)}catch(b){a.console.error(b)}}}a.TiledImage=function(b){var c=this;a.console.assert(b.tileCache,"[TiledImage] options.tileCache is required");a.console.assert(b.drawer,"[TiledImage] options.drawer is required");a.console.assert(b.viewer,"[TiledImage] options.viewer is required");a.console.assert(b.imageLoader,"[TiledImage] options.imageLoader is required");a.console.assert(b.source,"[TiledImage] options.source is required");a.console.assert(!b.clip||b.clip instanceof a.Rect,"[TiledImage] options.clip must be an OpenSeadragon.Rect if present");a.EventSource.call(this);this._tileCache=b.tileCache;delete b.tileCache;this._drawer=b.drawer;delete b.drawer;this._imageLoader=b.imageLoader;delete b.imageLoader;b.clip instanceof a.Rect&&(this._clip=b.clip.clone());delete b.clip;var d=b.x||0;delete b.x;var e=b.y||0;delete b.y;this.normHeight=b.source.dimensions.y/b.source.dimensions.x;this.contentAspectX=b.source.dimensions.x/b.source.dimensions.y;var f=1;if(b.width){f=b.width;delete b.width;if(b.height){a.console.error("specifying both width and height to a tiledImage is not supported");delete b.height}}else if(b.height){f=b.height/this.normHeight;delete b.height}var g=b.fitBounds;delete b.fitBounds;var h=b.fitBoundsPlacement||OpenSeadragon.Placement.CENTER;delete b.fitBoundsPlacement;var i=b.degrees||0;delete b.degrees;a.extend(!0,this,{viewer:null,tilesMatrix:{},coverage:{},loadingCoverage:{},lastDrawn:[],lastResetTime:0,_midDraw:!1,_needsDraw:!0,_hasOpaqueTile:!1,_tilesLoading:0,springStiffness:a.DEFAULT_SETTINGS.springStiffness,animationTime:a.DEFAULT_SETTINGS.animationTime,minZoomImageRatio:a.DEFAULT_SETTINGS.minZoomImageRatio,wrapHorizontal:a.DEFAULT_SETTINGS.wrapHorizontal,wrapVertical:a.DEFAULT_SETTINGS.wrapVertical,immediateRender:a.DEFAULT_SETTINGS.immediateRender,blendTime:a.DEFAULT_SETTINGS.blendTime,alwaysBlend:a.DEFAULT_SETTINGS.alwaysBlend,minPixelRatio:a.DEFAULT_SETTINGS.minPixelRatio,smoothTileEdgesMinZoom:a.DEFAULT_SETTINGS.smoothTileEdgesMinZoom,iOSDevice:a.DEFAULT_SETTINGS.iOSDevice,debugMode:a.DEFAULT_SETTINGS.debugMode,crossOriginPolicy:a.DEFAULT_SETTINGS.crossOriginPolicy,ajaxWithCredentials:a.DEFAULT_SETTINGS.ajaxWithCredentials,placeholderFillStyle:a.DEFAULT_SETTINGS.placeholderFillStyle,opacity:a.DEFAULT_SETTINGS.opacity,preload:a.DEFAULT_SETTINGS.preload,compositeOperation:a.DEFAULT_SETTINGS.compositeOperation},b);this._preload=this.preload;delete this.preload;this._fullyLoaded=!1;this._xSpring=new a.Spring({initial:d,springStiffness:this.springStiffness,animationTime:this.animationTime});this._ySpring=new a.Spring({initial:e,springStiffness:this.springStiffness,animationTime:this.animationTime});this._scaleSpring=new a.Spring({initial:f,springStiffness:this.springStiffness,animationTime:this.animationTime});this._degreesSpring=new a.Spring({initial:i,springStiffness:this.springStiffness,animationTime:this.animationTime});this._updateForScale();g&&this.fitBounds(g,h,!0);this._drawingHandler=function(b){c.viewer.raiseEvent("tile-drawing",a.extend({tiledImage:c},b))}};a.extend(a.TiledImage.prototype,a.EventSource.prototype,{needsDraw:function(){return this._needsDraw},getFullyLoaded:function(){return this._fullyLoaded},_setFullyLoaded:function(a){if(a!==this._fullyLoaded){this._fullyLoaded=a;this.raiseEvent("fully-loaded-change",{fullyLoaded:this._fullyLoaded})}},reset:function(){this._tileCache.clearTilesFor(this);this.lastResetTime=a.now();this._needsDraw=!0},update:function(){var a=this._xSpring.update();var b=this._ySpring.update();var c=this._scaleSpring.update();var d=this._degreesSpring.update();if(a||b||c||d){this._updateForScale();this._needsDraw=!0;return!0}return!1},draw:function(){if(0!==this.opacity||this._preload){this._midDraw=!0;this._updateViewport();this._midDraw=!1}},destroy:function(){this.reset()},getBounds:function(a){return this.getBoundsNoRotate(a).rotate(this.getRotation(a),this._getRotationPoint(a))},getBoundsNoRotate:function(b){return b?new a.Rect(this._xSpring.current.value,this._ySpring.current.value,this._worldWidthCurrent,this._worldHeightCurrent):new a.Rect(this._xSpring.target.value,this._ySpring.target.value,this._worldWidthTarget,this._worldHeightTarget)},getWorldBounds:function(){a.console.error("[TiledImage.getWorldBounds] is deprecated; use TiledImage.getBounds instead");return this.getBounds()},getClippedBounds:function(b){var c=this.getBoundsNoRotate(b);if(this._clip){var d=b?this._worldWidthCurrent:this._worldWidthTarget;var e=d/this.source.dimensions.x;var f=this._clip.times(e);c=new a.Rect(c.x+f.x,c.y+f.y,f.width,f.height)}return c.rotate(this.getRotation(b),this._getRotationPoint(b))},getContentSize:function(){return new a.Point(this.source.dimensions.x,this.source.dimensions.y)},_viewportToImageDelta:function(b,c,d){var e=d?this._scaleSpring.current.value:this._scaleSpring.target.value;return new a.Point(b*(this.source.dimensions.x/e),c*(this.source.dimensions.y*this.contentAspectX/e))},viewportToImageCoordinates:function(b,c,d){var e;if(b instanceof a.Point){d=c;e=b}else e=new a.Point(b,c);e=e.rotate(-this.getRotation(d),this._getRotationPoint(d));return d?this._viewportToImageDelta(e.x-this._xSpring.current.value,e.y-this._ySpring.current.value):this._viewportToImageDelta(e.x-this._xSpring.target.value,e.y-this._ySpring.target.value)},_imageToViewportDelta:function(b,c,d){var e=d?this._scaleSpring.current.value:this._scaleSpring.target.value;return new a.Point(b/this.source.dimensions.x*e,c/this.source.dimensions.y/this.contentAspectX*e)},imageToViewportCoordinates:function(b,c,d){if(b instanceof a.Point){d=c;c=b.y;b=b.x}var e=this._imageToViewportDelta(b,c);if(d){e.x+=this._xSpring.current.value;e.y+=this._ySpring.current.value}else{e.x+=this._xSpring.target.value;e.y+=this._ySpring.target.value}return e.rotate(this.getRotation(d),this._getRotationPoint(d))},imageToViewportRectangle:function(b,c,d,e,f){var g=b;g instanceof a.Rect?f=c:g=new a.Rect(b,c,d,e);var h=this.imageToViewportCoordinates(g.getTopLeft(),f);var i=this._imageToViewportDelta(g.width,g.height,f);return new a.Rect(h.x,h.y,i.x,i.y,g.degrees+this.getRotation(f))},viewportToImageRectangle:function(b,c,d,e,f){var g=b;b instanceof a.Rect?f=c:g=new a.Rect(b,c,d,e);var h=this.viewportToImageCoordinates(g.getTopLeft(),f);var i=this._viewportToImageDelta(g.width,g.height,f);return new a.Rect(h.x,h.y,i.x,i.y,g.degrees-this.getRotation(f))},viewerElementToImageCoordinates:function(a){var b=this.viewport.pointFromPixel(a,!0);return this.viewportToImageCoordinates(b)},imageToViewerElementCoordinates:function(a){var b=this.imageToViewportCoordinates(a);return this.viewport.pixelFromPoint(b,!0)},windowToImageCoordinates:function(a){var b=a.minus(OpenSeadragon.getElementPosition(this.viewer.element));return this.viewerElementToImageCoordinates(b)},imageToWindowCoordinates:function(a){var b=this.imageToViewerElementCoordinates(a);return b.plus(OpenSeadragon.getElementPosition(this.viewer.element))},_viewportToTiledImageRectangle:function(b){var c=this._scaleSpring.current.value;b=b.rotate(-this.getRotation(!0),this._getRotationPoint(!0));return new a.Rect((b.x-this._xSpring.current.value)/c,(b.y-this._ySpring.current.value)/c,b.width/c,b.height/c,b.degrees)},viewportToImageZoom:function(a){var b=this._scaleSpring.current.value*this.viewport._containerInnerSize.x/this.source.dimensions.x;return b*a},imageToViewportZoom:function(a){var b=this._scaleSpring.current.value*this.viewport._containerInnerSize.x/this.source.dimensions.x;return a/b},setPosition:function(a,b){var c=this._xSpring.target.value===a.x&&this._ySpring.target.value===a.y;if(b){if(c&&this._xSpring.current.value===a.x&&this._ySpring.current.value===a.y)return;this._xSpring.resetTo(a.x);this._ySpring.resetTo(a.y);this._needsDraw=!0}else{if(c)return;this._xSpring.springTo(a.x);this._ySpring.springTo(a.y);this._needsDraw=!0}c||this._raiseBoundsChange()},setWidth:function(a,b){this._setScale(a,b)},setHeight:function(a,b){this._setScale(a/this.normHeight,b)},fitBounds:function(b,c,d){c=c||a.Placement.CENTER;var e=a.Placement.properties[c];var f=this.contentAspectX;var g=0;var h=0;var i=1;var j=1;if(this._clip){f=this._clip.getAspectRatio();i=this._clip.width/this.source.dimensions.x;j=this._clip.height/this.source.dimensions.y;if(b.getAspectRatio()>f){g=this._clip.x/this._clip.height*b.height;h=this._clip.y/this._clip.height*b.height}else{g=this._clip.x/this._clip.width*b.width;h=this._clip.y/this._clip.width*b.width}}if(b.getAspectRatio()>f){var k=b.height/j;var l=0;e.isHorizontallyCentered?l=(b.width-b.height*f)/2:e.isRight&&(l=b.width-b.height*f);this.setPosition(new a.Point(b.x-g+l,b.y-h),d);this.setHeight(k,d)}else{var m=b.width/i;var n=0;e.isVerticallyCentered?n=(b.height-b.width/f)/2:e.isBottom&&(n=b.height-b.width/f);this.setPosition(new a.Point(b.x-g,b.y-h+n),d);this.setWidth(m,d)}},getClip:function(){return this._clip?this._clip.clone():null},setClip:function(b){a.console.assert(!b||b instanceof a.Rect,"[TiledImage.setClip] newClip must be an OpenSeadragon.Rect or null");b instanceof a.Rect?this._clip=b.clone():this._clip=null;this._needsDraw=!0;this.raiseEvent("clip-change")},getOpacity:function(){return this.opacity},setOpacity:function(a){if(a!==this.opacity){this.opacity=a;this._needsDraw=!0;this.raiseEvent("opacity-change",{opacity:this.opacity})}},getPreload:function(){return this._preload},setPreload:function(a){this._preload=!!a;this._needsDraw=!0},getRotation:function(a){return a?this._degreesSpring.current.value:this._degreesSpring.target.value},setRotation:function(a,b){if(this._degreesSpring.target.value!==a||!this._degreesSpring.isAtTargetValue()){b?this._degreesSpring.resetTo(a):this._degreesSpring.springTo(a);this._needsDraw=!0;this._raiseBoundsChange()}},_getRotationPoint:function(a){return this.getBoundsNoRotate(a).getCenter()},getCompositeOperation:function(){return this.compositeOperation},setCompositeOperation:function(a){if(a!==this.compositeOperation){this.compositeOperation=a;this._needsDraw=!0;this.raiseEvent("composite-operation-change",{compositeOperation:this.compositeOperation})}},_setScale:function(a,b){var c=this._scaleSpring.target.value===a;if(b){if(c&&this._scaleSpring.current.value===a)return;this._scaleSpring.resetTo(a);this._updateForScale();this._needsDraw=!0}else{if(c)return;this._scaleSpring.springTo(a);this._updateForScale();this._needsDraw=!0}c||this._raiseBoundsChange()},_updateForScale:function(){this._worldWidthTarget=this._scaleSpring.target.value;this._worldHeightTarget=this.normHeight*this._scaleSpring.target.value;this._worldWidthCurrent=this._scaleSpring.current.value;this._worldHeightCurrent=this.normHeight*this._scaleSpring.current.value},_raiseBoundsChange:function(){this.raiseEvent("bounds-change")},_isBottomItem:function(){return this.viewer.world.getItemAt(0)===this},_getLevelsInterval:function(){var a=Math.max(this.source.minLevel,Math.floor(Math.log(this.minZoomImageRatio)/Math.log(2)));var b=this.viewport.deltaPixelsFromPointsNoRotate(this.source.getPixelRatio(0),!0).x*this._scaleSpring.current.value;var c=Math.min(Math.abs(this.source.maxLevel),Math.abs(Math.floor(Math.log(b/this.minPixelRatio)/Math.log(2))));a=Math.min(a,c);return{lowestLevel:a,highestLevel:c}},_updateViewport:function(){this._needsDraw=!1;this._tilesLoading=0;this.loadingCoverage={};for(;this.lastDrawn.length>0;){var c=this.lastDrawn.pop();c.beingDrawn=!1}var d=this.viewport;var f=this._viewportToTiledImageRectangle(d.getBoundsWithMargins(!0));if(!this.wrapHorizontal&&!this.wrapVertical){var g=this._viewportToTiledImageRectangle(this.getClippedBounds(!0));f=f.intersection(g);if(null===f)return}var h=this._getLevelsInterval();var i=h.lowestLevel;var k=h.highestLevel;var l=null;var m=!1;var n=a.now();for(var p=k;p>=i;p--){var q=!1;var r=d.deltaPixelsFromPointsNoRotate(this.source.getPixelRatio(p),!0).x*this._scaleSpring.current.value;if(p===i||!m&&r>=this.minPixelRatio){q=!0;m=!0}else if(!m)continue;var s=d.deltaPixelsFromPointsNoRotate(this.source.getPixelRatio(p),!1).x*this._scaleSpring.current.value;var t=d.deltaPixelsFromPointsNoRotate(this.source.getPixelRatio(Math.max(this.source.getClosestLevel(),0)),!1).x*this._scaleSpring.current.value;var u=this.immediateRender?1:t;var v=Math.min(1,(r-.5)/.5);var w=u/Math.abs(u-s);l=b(this,m,q,p,v,w,f,n,l);if(j(this.coverage,p))break}o(this,this.lastDrawn);if(l&&!l.context2D){e(this,l,n);this._needsDraw=!0;this._setFullyLoaded(!1)}else this._setFullyLoaded(0===this._tilesLoading)},_getCornerTiles:function(b,c,d){var e;var f;if(this.wrapHorizontal){e=a.positiveModulo(c.x,1);f=a.positiveModulo(d.x,1)}else{e=Math.max(0,c.x);f=Math.min(1,d.x)}var g;var h;var i=1/this.source.aspectRatio;if(this.wrapVertical){g=a.positiveModulo(c.y,i);h=a.positiveModulo(d.y,i)}else{g=Math.max(0,c.y);h=Math.min(i,d.y)}var j=this.source.getTileAtPoint(b,new a.Point(e,g));var k=this.source.getTileAtPoint(b,new a.Point(f,h));var l=this.source.getNumTiles(b);if(this.wrapHorizontal){j.x+=l.x*Math.floor(c.x);k.x+=l.x*Math.floor(d.x)}if(this.wrapVertical){j.y+=l.y*Math.floor(c.y/i);k.y+=l.y*Math.floor(d.y/i)}return{topLeft:j,bottomRight:k}}})}(OpenSeadragon);!function(a){var b=function(b){a.console.assert(b,"[TileCache.cacheTile] options is required");a.console.assert(b.tile,"[TileCache.cacheTile] options.tile is required");a.console.assert(b.tiledImage,"[TileCache.cacheTile] options.tiledImage is required");this.tile=b.tile;this.tiledImage=b.tiledImage};var c=function(b){a.console.assert(b,"[ImageRecord] options is required");a.console.assert(b.image,"[ImageRecord] options.image is required");this._image=b.image;this._tiles=[]};c.prototype={destroy:function(){this._image=null;this._renderedContext=null;this._tiles=null},getImage:function(){return this._image},getRenderedContext:function(){if(!this._renderedContext){var a=document.createElement("canvas");a.width=this._image.width;a.height=this._image.height;this._renderedContext=a.getContext("2d");this._renderedContext.drawImage(this._image,0,0);this._image=null}return this._renderedContext},setRenderedContext:function(b){a.console.error("ImageRecord.setRenderedContext is deprecated. The rendered context should be created by the ImageRecord itself when calling ImageRecord.getRenderedContext.");this._renderedContext=b},addTile:function(b){a.console.assert(b,"[ImageRecord.addTile] tile is required");this._tiles.push(b)},removeTile:function(b){for(var c=0;cthis._maxImageCacheCount){var h=null;var i=-1;var j=null;var k,l,m,n,o,p;for(var q=this._tilesLoaded.length-1;q>=0;q--){p=this._tilesLoaded[q];k=p.tile;if(!(k.level<=e||k.beingDrawn))if(h){n=k.lastTouchTime;l=h.lastTouchTime;o=k.level;m=h.level;if(nm){h=k;i=q;j=p}}else{h=k;i=q;j=p}}if(h&&i>=0){this._unloadTile(j);f=i}}this._tilesLoaded[f]=new b({tile:d.tile,tiledImage:d.tiledImage})},clearTilesFor:function(b){a.console.assert(b,"[TileCache.clearTilesFor] tiledImage is required");var c;for(var d=0;d=this._items.length)throw new Error("Index bigger than number of layers.");if(c!==d&&d!==-1){this._items.splice(d,1);this._items.splice(c,0,b);this._needsDraw=!0;this.raiseEvent("item-index-change",{item:b,previousIndex:d,newIndex:c})}},removeItem:function(b){a.console.assert(b,"[World.removeItem] item is required");var c=a.indexOf(this._items,b);if(c!==-1){b.removeHandler("bounds-change",this._delegatedFigureSizes);b.removeHandler("clip-change",this._delegatedFigureSizes);b.destroy();this._items.splice(c,1);this._figureSizes();this._needsDraw=!0;this._raiseRemoveItem(b)}},removeAll:function(){this.viewer._cancelPendingImages();var a;var b;for(b=0;bn.height?g:g*(n.width/n.height);p=o*(n.height/n.width);q=new a.Point(k+(g-o)/2,l+(g-p)/2);m.setPosition(q,c);m.setWidth(o,c);"horizontal"===d?k+=i:l+=i}this.setAutoRefigureSizes(!0)},_figureSizes:function(){var b=this._homeBounds?this._homeBounds.clone():null;var c=this._contentSize?this._contentSize.clone():null;var d=this._contentFactor||0;if(this._items.length){var e=this._items[0];var f=e.getBounds();this._contentFactor=e.getContentSize().x/f.width;var g=e.getClippedBounds().getBoundingBox();var h=g.x;var i=g.y;var j=g.x+g.width;var k=g.y+g.height;for(var l=1;lDEPRECATED. A relative path to load a DZI file from the server.\n * Prefer the newer Options.tileSources.\n *\n * @property {String} [prefixUrl='/images/']\n * Prepends the prefixUrl to navImages paths, which is very useful\n * since the default paths are rarely useful for production\n * environments.\n *\n * @property {OpenSeadragon.NavImages} [navImages]\n * An object with a property for each button or other built-in navigation\n * control, eg the current 'zoomIn', 'zoomOut', 'home', and 'fullpage'.\n * Each of those in turn provides an image path for each state of the button\n * or navigation control, eg 'REST', 'GROUP', 'HOVER', 'PRESS'. Finally the\n * image paths, by default assume there is a folder on the servers root path\n * called '/images', eg '/images/zoomin_rest.png'. If you need to adjust\n * these paths, prefer setting the option.prefixUrl rather than overriding\n * every image path directly through this setting.\n *\n * @property {Boolean} [debugMode=false]\n * TODO: provide an in-screen panel providing event detail feedback.\n *\n * @property {String} [debugGridColor=['#437AB2', '#1B9E77', '#D95F02', '#7570B3', '#E7298A', '#66A61E', '#E6AB02', '#A6761D', '#666666']]\n * The colors of grids in debug mode. Each tiled image's grid uses a consecutive color.\n * If there are more tiled images than provided colors, the color vector is recycled.\n *\n * @property {Number} [blendTime=0]\n * Specifies the duration of animation as higher or lower level tiles are\n * replacing the existing tile.\n *\n * @property {Boolean} [alwaysBlend=false]\n * Forces the tile to always blend. By default the tiles skip blending\n * when the blendTime is surpassed and the current animation frame would\n * not complete the blend.\n *\n * @property {Boolean} [autoHideControls=true]\n * If the user stops interacting with the viewport, fade the navigation\n * controls. Useful for presentation since the controls are by default\n * floated on top of the image the user is viewing.\n *\n * @property {Boolean} [immediateRender=false]\n * Render the best closest level first, ignoring the lowering levels which\n * provide the effect of very blurry to sharp. It is recommended to change\n * setting to true for mobile devices.\n *\n * @property {Number} [defaultZoomLevel=0]\n * Zoom level to use when image is first opened or the home button is clicked.\n * If 0, adjusts to fit viewer.\n *\n * @property {Number} [opacity=1]\n * Default proportional opacity of the tiled images (1=opaque, 0=hidden)\n * Hidden images do not draw and only load when preloading is allowed.\n *\n * @property {Boolean} [preload=false]\n * Default switch for loading hidden images (true loads, false blocks)\n *\n * @property {String} [compositeOperation=null]\n * Valid values are 'source-over', 'source-atop', 'source-in', 'source-out',\n * 'destination-over', 'destination-atop', 'destination-in',\n * 'destination-out', 'lighter', 'copy' or 'xor'\n *\n * @property {String|CanvasGradient|CanvasPattern|Function} [placeholderFillStyle=null]\n * Draws a colored rectangle behind the tile if it is not loaded yet.\n * You can pass a CSS color value like \"#FF8800\".\n * When passing a function the tiledImage and canvas context are available as argument which is useful when you draw a gradient or pattern.\n *\n * @property {Number} [degrees=0]\n * Initial rotation.\n *\n * @property {Number} [minZoomLevel=null]\n *\n * @property {Number} [maxZoomLevel=null]\n *\n * @property {Boolean} [homeFillsViewer=false]\n * Make the 'home' button fill the viewer and clip the image, instead\n * of fitting the image to the viewer and letterboxing.\n *\n * @property {Boolean} [panHorizontal=true]\n * Allow horizontal pan.\n *\n * @property {Boolean} [panVertical=true]\n * Allow vertical pan.\n *\n * @property {Boolean} [constrainDuringPan=false]\n *\n * @property {Boolean} [wrapHorizontal=false]\n * Set to true to force the image to wrap horizontally within the viewport.\n * Useful for maps or images representing the surface of a sphere or cylinder.\n *\n * @property {Boolean} [wrapVertical=false]\n * Set to true to force the image to wrap vertically within the viewport.\n * Useful for maps or images representing the surface of a sphere or cylinder.\n *\n * @property {Number} [minZoomImageRatio=0.9]\n * The minimum percentage ( expressed as a number between 0 and 1 ) of\n * the viewport height or width at which the zoom out will be constrained.\n * Setting it to 0, for example will allow you to zoom out infinity.\n *\n * @property {Number} [maxZoomPixelRatio=1.1]\n * The maximum ratio to allow a zoom-in to affect the highest level pixel\n * ratio. This can be set to Infinity to allow 'infinite' zooming into the\n * image though it is less effective visually if the HTML5 Canvas is not\n * availble on the viewing device.\n *\n * @property {Number} [smoothTileEdgesMinZoom=1.1]\n * A zoom percentage ( where 1 is 100% ) of the highest resolution level.\n * When zoomed in beyond this value alternative compositing will be used to\n * smooth out the edges between tiles. This will have a performance impact.\n * Can be set to Infinity to turn it off.\n * Note: This setting is ignored on iOS devices due to a known bug (See {@link https://github.com/openseadragon/openseadragon/issues/952})\n *\n * @property {Boolean} [iOSDevice=?]\n * True if running on an iOS device, false otherwise.\n * Used to disable certain features that behave differently on iOS devices.\n *\n * @property {Boolean} [autoResize=true]\n * Set to false to prevent polling for viewer size changes. Useful for providing custom resize behavior.\n *\n * @property {Boolean} [preserveImageSizeOnResize=false]\n * Set to true to have the image size preserved when the viewer is resized. This requires autoResize=true (default).\n *\n * @property {Number} [minScrollDeltaTime=50]\n * Number of milliseconds between canvas-scroll events. This value helps normalize the rate of canvas-scroll\n * events between different devices, causing the faster devices to slow down enough to make the zoom control\n * more manageable.\n *\n * @property {Number} [pixelsPerWheelLine=40]\n * For pixel-resolution scrolling devices, the number of pixels equal to one scroll line.\n *\n * @property {Number} [visibilityRatio=0.5]\n * The percentage ( as a number from 0 to 1 ) of the source image which\n * must be kept within the viewport. If the image is dragged beyond that\n * limit, it will 'bounce' back until the minimum visibility ratio is\n * achieved. Setting this to 0 and wrapHorizontal ( or wrapVertical ) to\n * true will provide the effect of an infinitely scrolling viewport.\n *\n * @property {Object} [viewportMargins={}]\n * Pushes the \"home\" region in from the sides by the specified amounts.\n * Possible subproperties (Numbers, in screen coordinates): left, top, right, bottom.\n *\n * @property {Number} [imageLoaderLimit=0]\n * The maximum number of image requests to make concurrently. By default\n * it is set to 0 allowing the browser to make the maximum number of\n * image requests in parallel as allowed by the browsers policy.\n *\n * @property {Number} [clickTimeThreshold=300]\n * The number of milliseconds within which a pointer down-up event combination\n * will be treated as a click gesture.\n *\n * @property {Number} [clickDistThreshold=5]\n * The maximum distance allowed between a pointer down event and a pointer up event\n * to be treated as a click gesture.\n *\n * @property {Number} [dblClickTimeThreshold=300]\n * The number of milliseconds within which two pointer down-up event combinations\n * will be treated as a double-click gesture.\n *\n * @property {Number} [dblClickDistThreshold=20]\n * The maximum distance allowed between two pointer click events\n * to be treated as a double-click gesture.\n *\n * @property {Number} [springStiffness=6.5]\n *\n * @property {Number} [animationTime=1.2]\n * Specifies the animation duration per each {@link OpenSeadragon.Spring}\n * which occur when the image is dragged or zoomed.\n *\n * @property {OpenSeadragon.GestureSettings} [gestureSettingsMouse]\n * Settings for gestures generated by a mouse pointer device. (See {@link OpenSeadragon.GestureSettings})\n * @property {Boolean} [gestureSettingsMouse.scrollToZoom=true] - Zoom on scroll gesture\n * @property {Boolean} [gestureSettingsMouse.clickToZoom=true] - Zoom on click gesture\n * @property {Boolean} [gestureSettingsMouse.dblClickToZoom=false] - Zoom on double-click gesture. Note: If set to true\n * then clickToZoom should be set to false to prevent multiple zooms.\n * @property {Boolean} [gestureSettingsMouse.pinchToZoom=false] - Zoom on pinch gesture\n * @property {Boolean} [gestureSettingsMouse.flickEnabled=false] - Enable flick gesture\n * @property {Number} [gestureSettingsMouse.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)\n * @property {Number} [gestureSettingsMouse.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture\n * @property {Boolean} [gestureSettingsMouse.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers.\n *\n * @property {OpenSeadragon.GestureSettings} [gestureSettingsTouch]\n * Settings for gestures generated by a touch pointer device. (See {@link OpenSeadragon.GestureSettings})\n * @property {Boolean} [gestureSettingsTouch.scrollToZoom=false] - Zoom on scroll gesture\n * @property {Boolean} [gestureSettingsTouch.clickToZoom=false] - Zoom on click gesture\n * @property {Boolean} [gestureSettingsTouch.dblClickToZoom=true] - Zoom on double-click gesture. Note: If set to true\n * then clickToZoom should be set to false to prevent multiple zooms.\n * @property {Boolean} [gestureSettingsTouch.pinchToZoom=true] - Zoom on pinch gesture\n * @property {Boolean} [gestureSettingsTouch.flickEnabled=true] - Enable flick gesture\n * @property {Number} [gestureSettingsTouch.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)\n * @property {Number} [gestureSettingsTouch.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture\n * @property {Boolean} [gestureSettingsTouch.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers.\n *\n * @property {OpenSeadragon.GestureSettings} [gestureSettingsPen]\n * Settings for gestures generated by a pen pointer device. (See {@link OpenSeadragon.GestureSettings})\n * @property {Boolean} [gestureSettingsPen.scrollToZoom=false] - Zoom on scroll gesture\n * @property {Boolean} [gestureSettingsPen.clickToZoom=true] - Zoom on click gesture\n * @property {Boolean} [gestureSettingsPen.dblClickToZoom=false] - Zoom on double-click gesture. Note: If set to true\n * then clickToZoom should be set to false to prevent multiple zooms.\n * @property {Boolean} [gestureSettingsPen.pinchToZoom=false] - Zoom on pinch gesture\n * @property {Boolean} [gestureSettingsPen.flickEnabled=false] - Enable flick gesture\n * @property {Number} [gestureSettingsPen.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)\n * @property {Number} [gestureSettingsPen.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture\n * @property {Boolean} [gestureSettingsPen.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers.\n *\n * @property {OpenSeadragon.GestureSettings} [gestureSettingsUnknown]\n * Settings for gestures generated by unknown pointer devices. (See {@link OpenSeadragon.GestureSettings})\n * @property {Boolean} [gestureSettingsUnknown.scrollToZoom=true] - Zoom on scroll gesture\n * @property {Boolean} [gestureSettingsUnknown.clickToZoom=false] - Zoom on click gesture\n * @property {Boolean} [gestureSettingsUnknown.dblClickToZoom=true] - Zoom on double-click gesture. Note: If set to true\n * then clickToZoom should be set to false to prevent multiple zooms.\n * @property {Boolean} [gestureSettingsUnknown.pinchToZoom=true] - Zoom on pinch gesture\n * @property {Boolean} [gestureSettingsUnknown.flickEnabled=true] - Enable flick gesture\n * @property {Number} [gestureSettingsUnknown.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)\n * @property {Number} [gestureSettingsUnknown.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture\n * @property {Boolean} [gestureSettingsUnknown.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers.\n *\n * @property {Number} [zoomPerClick=2.0]\n * The \"zoom distance\" per mouse click or touch tap. Note: Setting this to 1.0 effectively disables the click-to-zoom feature (also see gestureSettings[Mouse|Touch|Pen].clickToZoom/dblClickToZoom).\n *\n * @property {Number} [zoomPerScroll=1.2]\n * The \"zoom distance\" per mouse scroll or touch pinch. Note: Setting this to 1.0 effectively disables the mouse-wheel zoom feature (also see gestureSettings[Mouse|Touch|Pen].scrollToZoom}).\n *\n * @property {Number} [zoomPerSecond=1.0]\n * The number of seconds to animate a single zoom event over.\n *\n * @property {Boolean} [showNavigator=false]\n * Set to true to make the navigator minimap appear.\n *\n * @property {String} [navigatorId=navigator-GENERATED DATE]\n * The ID of a div to hold the navigator minimap.\n * If an ID is specified, the navigatorPosition, navigatorSizeRatio, navigatorMaintainSizeRatio, navigator[Top|Left|Height|Width] and navigatorAutoFade options will be ignored.\n * If an ID is not specified, a div element will be generated and placed on top of the main image.\n *\n * @property {String} [navigatorPosition='TOP_RIGHT']\n * Valid values are 'TOP_LEFT', 'TOP_RIGHT', 'BOTTOM_LEFT', 'BOTTOM_RIGHT', or 'ABSOLUTE'.
      \n * If 'ABSOLUTE' is specified, then navigator[Top|Left|Height|Width] determines the size and position of the navigator minimap in the viewer, and navigatorSizeRatio and navigatorMaintainSizeRatio are ignored.
      \n * For 'TOP_LEFT', 'TOP_RIGHT', 'BOTTOM_LEFT', and 'BOTTOM_RIGHT', the navigatorSizeRatio or navigator[Height|Width] values determine the size of the navigator minimap.\n *\n * @property {Number} [navigatorSizeRatio=0.2]\n * Ratio of navigator size to viewer size. Ignored if navigator[Height|Width] are specified.\n *\n * @property {Boolean} [navigatorMaintainSizeRatio=false]\n * If true, the navigator minimap is resized (using navigatorSizeRatio) when the viewer size changes.\n *\n * @property {Number|String} [navigatorTop=null]\n * Specifies the location of the navigator minimap (see navigatorPosition).\n *\n * @property {Number|String} [navigatorLeft=null]\n * Specifies the location of the navigator minimap (see navigatorPosition).\n *\n * @property {Number|String} [navigatorHeight=null]\n * Specifies the size of the navigator minimap (see navigatorPosition).\n * If specified, navigatorSizeRatio and navigatorMaintainSizeRatio are ignored.\n *\n * @property {Number|String} [navigatorWidth=null]\n * Specifies the size of the navigator minimap (see navigatorPosition).\n * If specified, navigatorSizeRatio and navigatorMaintainSizeRatio are ignored.\n *\n * @property {Boolean} [navigatorAutoResize=true]\n * Set to false to prevent polling for navigator size changes. Useful for providing custom resize behavior.\n * Setting to false can also improve performance when the navigator is configured to a fixed size.\n *\n * @property {Boolean} [navigatorAutoFade=true]\n * If the user stops interacting with the viewport, fade the navigator minimap.\n * Setting to false will make the navigator minimap always visible.\n *\n * @property {Boolean} [navigatorRotate=true]\n * If true, the navigator will be rotated together with the viewer.\n *\n * @property {Number} [controlsFadeDelay=2000]\n * The number of milliseconds to wait once the user has stopped interacting\n * with the interface before begining to fade the controls. Assumes\n * showNavigationControl and autoHideControls are both true.\n *\n * @property {Number} [controlsFadeLength=1500]\n * The number of milliseconds to animate the controls fading out.\n *\n * @property {Number} [maxImageCacheCount=200]\n * The max number of images we should keep in memory (per drawer).\n *\n * @property {Number} [timeout=30000]\n * The max number of milliseconds that an image job may take to complete.\n *\n * @property {Boolean} [useCanvas=true]\n * Set to false to not use an HTML canvas element for image rendering even if canvas is supported.\n *\n * @property {Number} [minPixelRatio=0.5]\n * The higher the minPixelRatio, the lower the quality of the image that\n * is considered sufficient to stop rendering a given zoom level. For\n * example, if you are targeting mobile devices with less bandwith you may\n * try setting this to 1.5 or higher.\n *\n * @property {Boolean} [mouseNavEnabled=true]\n * Is the user able to interact with the image via mouse or touch. Default\n * interactions include draging the image in a plane, and zooming in toward\n * and away from the image.\n *\n * @property {Boolean} [showNavigationControl=true]\n * Set to false to prevent the appearance of the default navigation controls.
      \n * Note that if set to false, the customs buttons set by the options\n * zoomInButton, zoomOutButton etc, are rendered inactive.\n *\n * @property {OpenSeadragon.ControlAnchor} [navigationControlAnchor=TOP_LEFT]\n * Placement of the default navigation controls.\n * To set the placement of the sequence controls, see the\n * sequenceControlAnchor option.\n *\n * @property {Boolean} [showZoomControl=true]\n * If true then + and - buttons to zoom in and out are displayed.
      \n * Note: {@link OpenSeadragon.Options.showNavigationControl} is overriding\n * this setting when set to false.\n *\n * @property {Boolean} [showHomeControl=true]\n * If true then the 'Go home' button is displayed to go back to the original\n * zoom and pan.
      \n * Note: {@link OpenSeadragon.Options.showNavigationControl} is overriding\n * this setting when set to false.\n *\n * @property {Boolean} [showFullPageControl=true]\n * If true then the 'Toggle full page' button is displayed to switch\n * between full page and normal mode.
      \n * Note: {@link OpenSeadragon.Options.showNavigationControl} is overriding\n * this setting when set to false.\n *\n * @property {Boolean} [showRotationControl=false]\n * If true then the rotate left/right controls will be displayed as part of the\n * standard controls. This is also subject to the browser support for rotate\n * (e.g. viewer.drawer.canRotate()).
      \n * Note: {@link OpenSeadragon.Options.showNavigationControl} is overriding\n * this setting when set to false.\n *\n * @property {Boolean} [showSequenceControl=true]\n * If sequenceMode is true, then provide buttons for navigating forward and\n * backward through the images.\n *\n * @property {OpenSeadragon.ControlAnchor} [sequenceControlAnchor=TOP_LEFT]\n * Placement of the default sequence controls.\n *\n * @property {Boolean} [navPrevNextWrap=false]\n * If true then the 'previous' button will wrap to the last image when\n * viewing the first image and the 'next' button will wrap to the first\n * image when viewing the last image.\n *\n * @property {String} zoomInButton\n * Set the id of the custom 'Zoom in' button to use.\n * This is useful to have a custom button anywhere in the web page.
      \n * To only change the button images, consider using\n * {@link OpenSeadragon.Options.navImages}\n *\n * @property {String} zoomOutButton\n * Set the id of the custom 'Zoom out' button to use.\n * This is useful to have a custom button anywhere in the web page.
      \n * To only change the button images, consider using\n * {@link OpenSeadragon.Options.navImages}\n *\n * @property {String} homeButton\n * Set the id of the custom 'Go home' button to use.\n * This is useful to have a custom button anywhere in the web page.
      \n * To only change the button images, consider using\n * {@link OpenSeadragon.Options.navImages}\n *\n * @property {String} fullPageButton\n * Set the id of the custom 'Toggle full page' button to use.\n * This is useful to have a custom button anywhere in the web page.
      \n * To only change the button images, consider using\n * {@link OpenSeadragon.Options.navImages}\n *\n * @property {String} rotateLeftButton\n * Set the id of the custom 'Rotate left' button to use.\n * This is useful to have a custom button anywhere in the web page.
      \n * To only change the button images, consider using\n * {@link OpenSeadragon.Options.navImages}\n *\n * @property {String} rotateRightButton\n * Set the id of the custom 'Rotate right' button to use.\n * This is useful to have a custom button anywhere in the web page.
      \n * To only change the button images, consider using\n * {@link OpenSeadragon.Options.navImages}\n *\n * @property {String} previousButton\n * Set the id of the custom 'Previous page' button to use.\n * This is useful to have a custom button anywhere in the web page.
      \n * To only change the button images, consider using\n * {@link OpenSeadragon.Options.navImages}\n *\n * @property {String} nextButton\n * Set the id of the custom 'Next page' button to use.\n * This is useful to have a custom button anywhere in the web page.
      \n * To only change the button images, consider using\n * {@link OpenSeadragon.Options.navImages}\n *\n * @property {Boolean} [sequenceMode=false]\n * Set to true to have the viewer treat your tilesources as a sequence of images to\n * be opened one at a time rather than all at once.\n *\n * @property {Number} [initialPage=0]\n * If sequenceMode is true, display this page initially.\n *\n * @property {Boolean} [preserveViewport=false]\n * If sequenceMode is true, then normally navigating through each image resets the\n * viewport to 'home' position. If preserveViewport is set to true, then the viewport\n * position is preserved when navigating between images in the sequence.\n *\n * @property {Boolean} [preserveOverlays=false]\n * If sequenceMode is true, then normally navigating through each image\n * resets the overlays.\n * If preserveOverlays is set to true, then the overlays added with {@link OpenSeadragon.Viewer#addOverlay}\n * are preserved when navigating between images in the sequence.\n * Note: setting preserveOverlays overrides any overlays specified in the global\n * \"overlays\" option for the Viewer. It's also not compatible with specifying\n * per-tileSource overlays via the options, as those overlays will persist\n * even after the tileSource is closed.\n *\n * @property {Boolean} [showReferenceStrip=false]\n * If sequenceMode is true, then display a scrolling strip of image thumbnails for\n * navigating through the images.\n *\n * @property {String} [referenceStripScroll='horizontal']\n *\n * @property {Element} [referenceStripElement=null]\n *\n * @property {Number} [referenceStripHeight=null]\n *\n * @property {Number} [referenceStripWidth=null]\n *\n * @property {String} [referenceStripPosition='BOTTOM_LEFT']\n *\n * @property {Number} [referenceStripSizeRatio=0.2]\n *\n * @property {Boolean} [collectionMode=false]\n * Set to true to have the viewer arrange your TiledImages in a grid or line.\n *\n * @property {Number} [collectionRows=3]\n * If collectionMode is true, specifies how many rows the grid should have. Use 1 to make a line.\n * If collectionLayout is 'vertical', specifies how many columns instead.\n *\n * @property {Number} [collectionColumns=0]\n * If collectionMode is true, specifies how many columns the grid should have. Use 1 to make a line.\n * If collectionLayout is 'vertical', specifies how many rows instead. Ignored if collectionRows is not set to a falsy value.\n *\n * @property {String} [collectionLayout='horizontal']\n * If collectionMode is true, specifies whether to arrange vertically or horizontally.\n *\n * @property {Number} [collectionTileSize=800]\n * If collectionMode is true, specifies the size, in viewport coordinates, for each TiledImage to fit into.\n * The TiledImage will be centered within a square of the specified size.\n *\n * @property {Number} [collectionTileMargin=80]\n * If collectionMode is true, specifies the margin, in viewport coordinates, between each TiledImage.\n *\n * @property {String|Boolean} [crossOriginPolicy=false]\n * Valid values are 'Anonymous', 'use-credentials', and false. If false, canvas requests will\n * not use CORS, and the canvas will be tainted.\n *\n * @property {Boolean} [ajaxWithCredentials=false]\n * Whether to set the withCredentials XHR flag for AJAX requests.\n * Note that this can be overridden at the {@link OpenSeadragon.TileSource} level.\n *\n * @property {Boolean} [loadTilesWithAjax=false]\n * Whether to load tile data using AJAX requests.\n * Note that this can be overridden at the {@link OpenSeadragon.TileSource} level.\n *\n * @property {Object} [ajaxHeaders={}]\n * A set of headers to include when making AJAX requests for tile sources or tiles.\n *\n */\n\n /**\n * Settings for gestures generated by a pointer device.\n *\n * @typedef {Object} GestureSettings\n * @memberof OpenSeadragon\n *\n * @property {Boolean} scrollToZoom\n * Set to false to disable zooming on scroll gestures.\n *\n * @property {Boolean} clickToZoom\n * Set to false to disable zooming on click gestures.\n *\n * @property {Boolean} dblClickToZoom\n * Set to false to disable zooming on double-click gestures. Note: If set to true\n * then clickToZoom should be set to false to prevent multiple zooms.\n *\n * @property {Boolean} pinchToZoom\n * Set to false to disable zooming on pinch gestures.\n *\n * @property {Boolean} flickEnabled\n * Set to false to disable the kinetic panning effect (flick) at the end of a drag gesture.\n *\n * @property {Number} flickMinSpeed\n * If flickEnabled is true, the minimum speed (in pixels-per-second) required to cause the kinetic panning effect (flick) at the end of a drag gesture.\n *\n * @property {Number} flickMomentum\n * If flickEnabled is true, a constant multiplied by the velocity to determine the distance of the kinetic panning effect (flick) at the end of a drag gesture.\n * A larger value will make the flick feel \"lighter\", while a smaller value will make the flick feel \"heavier\".\n * Note: springStiffness and animationTime also affect the \"spring\" used to stop the flick animation.\n *\n */\n\n/**\n * The names for the image resources used for the image navigation buttons.\n *\n * @typedef {Object} NavImages\n * @memberof OpenSeadragon\n *\n * @property {Object} zoomIn - Images for the zoom-in button.\n * @property {String} zoomIn.REST\n * @property {String} zoomIn.GROUP\n * @property {String} zoomIn.HOVER\n * @property {String} zoomIn.DOWN\n *\n * @property {Object} zoomOut - Images for the zoom-out button.\n * @property {String} zoomOut.REST\n * @property {String} zoomOut.GROUP\n * @property {String} zoomOut.HOVER\n * @property {String} zoomOut.DOWN\n *\n * @property {Object} home - Images for the home button.\n * @property {String} home.REST\n * @property {String} home.GROUP\n * @property {String} home.HOVER\n * @property {String} home.DOWN\n *\n * @property {Object} fullpage - Images for the full-page button.\n * @property {String} fullpage.REST\n * @property {String} fullpage.GROUP\n * @property {String} fullpage.HOVER\n * @property {String} fullpage.DOWN\n *\n * @property {Object} rotateleft - Images for the rotate left button.\n * @property {String} rotateleft.REST\n * @property {String} rotateleft.GROUP\n * @property {String} rotateleft.HOVER\n * @property {String} rotateleft.DOWN\n *\n * @property {Object} rotateright - Images for the rotate right button.\n * @property {String} rotateright.REST\n * @property {String} rotateright.GROUP\n * @property {String} rotateright.HOVER\n * @property {String} rotateright.DOWN\n *\n * @property {Object} previous - Images for the previous button.\n * @property {String} previous.REST\n * @property {String} previous.GROUP\n * @property {String} previous.HOVER\n * @property {String} previous.DOWN\n *\n * @property {Object} next - Images for the next button.\n * @property {String} next.REST\n * @property {String} next.GROUP\n * @property {String} next.HOVER\n * @property {String} next.DOWN\n *\n */\n\n\nfunction OpenSeadragon( options ){\n return new OpenSeadragon.Viewer( options );\n}\n\n(function( $ ){\n\n\n /**\n * The OpenSeadragon version.\n *\n * @member {Object} OpenSeadragon.version\n * @property {String} versionStr - The version number as a string ('major.minor.revision').\n * @property {Number} major - The major version number.\n * @property {Number} minor - The minor version number.\n * @property {Number} revision - The revision number.\n * @since 1.0.0\n */\n $.version = {\n versionStr: '2.3.1',\n major: parseInt('2', 10),\n minor: parseInt('3', 10),\n revision: parseInt('1', 10)\n };\n\n\n /**\n * Taken from jquery 1.6.1\n * [[Class]] -> type pairs\n * @private\n */\n var class2type = {\n '[object Boolean]': 'boolean',\n '[object Number]': 'number',\n '[object String]': 'string',\n '[object Function]': 'function',\n '[object Array]': 'array',\n '[object Date]': 'date',\n '[object RegExp]': 'regexp',\n '[object Object]': 'object'\n },\n // Save a reference to some core methods\n toString = Object.prototype.toString,\n hasOwn = Object.prototype.hasOwnProperty;\n\n /**\n * Taken from jQuery 1.6.1\n * @function isFunction\n * @memberof OpenSeadragon\n * @see {@link http://www.jquery.com/ jQuery}\n */\n $.isFunction = function( obj ) {\n return $.type(obj) === \"function\";\n };\n\n\n /**\n * Taken from jQuery 1.6.1\n * @function isArray\n * @memberof OpenSeadragon\n * @see {@link http://www.jquery.com/ jQuery}\n */\n $.isArray = Array.isArray || function( obj ) {\n return $.type(obj) === \"array\";\n };\n\n\n /**\n * A crude way of determining if an object is a window.\n * Taken from jQuery 1.6.1\n * @function isWindow\n * @memberof OpenSeadragon\n * @see {@link http://www.jquery.com/ jQuery}\n */\n $.isWindow = function( obj ) {\n return obj && typeof obj === \"object\" && \"setInterval\" in obj;\n };\n\n\n /**\n * Taken from jQuery 1.6.1\n * @function type\n * @memberof OpenSeadragon\n * @see {@link http://www.jquery.com/ jQuery}\n */\n $.type = function( obj ) {\n return ( obj === null ) || ( obj === undefined ) ?\n String( obj ) :\n class2type[ toString.call(obj) ] || \"object\";\n };\n\n\n /**\n * Taken from jQuery 1.6.1\n * @function isPlainObject\n * @memberof OpenSeadragon\n * @see {@link http://www.jquery.com/ jQuery}\n */\n $.isPlainObject = function( obj ) {\n // Must be an Object.\n // Because of IE, we also have to check the presence of the constructor property.\n // Make sure that DOM nodes and window objects don't pass through, as well\n if ( !obj || OpenSeadragon.type(obj) !== \"object\" || obj.nodeType || $.isWindow( obj ) ) {\n return false;\n }\n\n // Not own constructor property must be Object\n if ( obj.constructor &&\n !hasOwn.call(obj, \"constructor\") &&\n !hasOwn.call(obj.constructor.prototype, \"isPrototypeOf\") ) {\n return false;\n }\n\n // Own properties are enumerated firstly, so to speed up,\n // if last one is own, then all properties are own.\n\n var lastKey;\n for (var key in obj ) {\n lastKey = key;\n }\n\n return lastKey === undefined || hasOwn.call( obj, lastKey );\n };\n\n\n /**\n * Taken from jQuery 1.6.1\n * @function isEmptyObject\n * @memberof OpenSeadragon\n * @see {@link http://www.jquery.com/ jQuery}\n */\n $.isEmptyObject = function( obj ) {\n for ( var name in obj ) {\n return false;\n }\n return true;\n };\n\n /**\n * Shim around Object.freeze. Does nothing if Object.freeze is not supported.\n * @param {Object} obj The object to freeze.\n * @return {Object} obj The frozen object.\n */\n $.freezeObject = function(obj) {\n if (Object.freeze) {\n $.freezeObject = Object.freeze;\n } else {\n $.freezeObject = function(obj) {\n return obj;\n };\n }\n return $.freezeObject(obj);\n };\n\n /**\n * True if the browser supports the HTML5 canvas element\n * @member {Boolean} supportsCanvas\n * @memberof OpenSeadragon\n */\n $.supportsCanvas = (function () {\n var canvasElement = document.createElement( 'canvas' );\n return !!( $.isFunction( canvasElement.getContext ) &&\n canvasElement.getContext( '2d' ) );\n }());\n\n /**\n * Test whether the submitted canvas is tainted or not.\n * @argument {Canvas} canvas The canvas to test.\n * @returns {Boolean} True if the canvas is tainted.\n */\n $.isCanvasTainted = function(canvas) {\n var isTainted = false;\n try {\n // We test if the canvas is tainted by retrieving data from it.\n // An exception will be raised if the canvas is tainted.\n canvas.getContext('2d').getImageData(0, 0, 1, 1);\n } catch (e) {\n isTainted = true;\n }\n return isTainted;\n };\n\n /**\n * A ratio comparing the device screen's pixel density to the canvas's backing store pixel density,\n * clamped to a minimum of 1. Defaults to 1 if canvas isn't supported by the browser.\n * @member {Number} pixelDensityRatio\n * @memberof OpenSeadragon\n */\n $.pixelDensityRatio = (function () {\n if ( $.supportsCanvas ) {\n var context = document.createElement('canvas').getContext('2d');\n var devicePixelRatio = window.devicePixelRatio || 1;\n var backingStoreRatio = context.webkitBackingStorePixelRatio ||\n context.mozBackingStorePixelRatio ||\n context.msBackingStorePixelRatio ||\n context.oBackingStorePixelRatio ||\n context.backingStorePixelRatio || 1;\n return Math.max(devicePixelRatio, 1) / backingStoreRatio;\n } else {\n return 1;\n }\n }());\n\n}( OpenSeadragon ));\n\n/**\n * This closure defines all static methods available to the OpenSeadragon\n * namespace. Many, if not most, are taked directly from jQuery for use\n * to simplify and reduce common programming patterns. More static methods\n * from jQuery may eventually make their way into this though we are\n * attempting to avoid an explicit dependency on jQuery only because\n * OpenSeadragon is a broadly useful code base and would be made less broad\n * by requiring jQuery fully.\n *\n * Some static methods have also been refactored from the original OpenSeadragon\n * project.\n */\n(function( $ ){\n\n /**\n * Taken from jQuery 1.6.1\n * @function extend\n * @memberof OpenSeadragon\n * @see {@link http://www.jquery.com/ jQuery}\n */\n $.extend = function() {\n var options,\n name,\n src,\n copy,\n copyIsArray,\n clone,\n target = arguments[ 0 ] || {},\n length = arguments.length,\n deep = false,\n i = 1;\n\n // Handle a deep copy situation\n if ( typeof target === \"boolean\" ) {\n deep = target;\n target = arguments[ 1 ] || {};\n // skip the boolean and the target\n i = 2;\n }\n\n // Handle case when target is a string or something (possible in deep copy)\n if ( typeof target !== \"object\" && !OpenSeadragon.isFunction( target ) ) {\n target = {};\n }\n\n // extend jQuery itself if only one argument is passed\n if ( length === i ) {\n target = this;\n --i;\n }\n\n for ( ; i < length; i++ ) {\n // Only deal with non-null/undefined values\n options = arguments[ i ];\n if ( options !== null || options !== undefined ) {\n // Extend the base object\n for ( name in options ) {\n src = target[ name ];\n copy = options[ name ];\n\n // Prevent never-ending loop\n if ( target === copy ) {\n continue;\n }\n\n // Recurse if we're merging plain objects or arrays\n if ( deep && copy && ( OpenSeadragon.isPlainObject( copy ) || ( copyIsArray = OpenSeadragon.isArray( copy ) ) ) ) {\n if ( copyIsArray ) {\n copyIsArray = false;\n clone = src && OpenSeadragon.isArray( src ) ? src : [];\n\n } else {\n clone = src && OpenSeadragon.isPlainObject( src ) ? src : {};\n }\n\n // Never move original objects, clone them\n target[ name ] = OpenSeadragon.extend( deep, clone, copy );\n\n // Don't bring in undefined values\n } else if ( copy !== undefined ) {\n target[ name ] = copy;\n }\n }\n }\n }\n\n // Return the modified object\n return target;\n };\n\n var isIOSDevice = function () {\n if (typeof navigator !== 'object') {\n return false;\n }\n var userAgent = navigator.userAgent;\n if (typeof userAgent !== 'string') {\n return false;\n }\n return userAgent.indexOf('iPhone') !== -1 ||\n userAgent.indexOf('iPad') !== -1 ||\n userAgent.indexOf('iPod') !== -1;\n };\n\n $.extend( $, /** @lends OpenSeadragon */{\n /**\n * The default values for the optional settings documented at {@link OpenSeadragon.Options}.\n * @static\n * @type {Object}\n */\n DEFAULT_SETTINGS: {\n //DATA SOURCE DETAILS\n xmlPath: null,\n tileSources: null,\n tileHost: null,\n initialPage: 0,\n crossOriginPolicy: false,\n ajaxWithCredentials: false,\n loadTilesWithAjax: false,\n ajaxHeaders: {},\n\n //PAN AND ZOOM SETTINGS AND CONSTRAINTS\n panHorizontal: true,\n panVertical: true,\n constrainDuringPan: false,\n wrapHorizontal: false,\n wrapVertical: false,\n visibilityRatio: 0.5, //-> how much of the viewer can be negative space\n minPixelRatio: 0.5, //->closer to 0 draws tiles meant for a higher zoom at this zoom\n defaultZoomLevel: 0,\n minZoomLevel: null,\n maxZoomLevel: null,\n homeFillsViewer: false,\n\n //UI RESPONSIVENESS AND FEEL\n clickTimeThreshold: 300,\n clickDistThreshold: 5,\n dblClickTimeThreshold: 300,\n dblClickDistThreshold: 20,\n springStiffness: 6.5,\n animationTime: 1.2,\n gestureSettingsMouse: {\n scrollToZoom: true,\n clickToZoom: true,\n dblClickToZoom: false,\n pinchToZoom: false,\n flickEnabled: false,\n flickMinSpeed: 120,\n flickMomentum: 0.25,\n pinchRotate: false\n },\n gestureSettingsTouch: {\n scrollToZoom: false,\n clickToZoom: false,\n dblClickToZoom: true,\n pinchToZoom: true,\n flickEnabled: true,\n flickMinSpeed: 120,\n flickMomentum: 0.25,\n pinchRotate: false\n },\n gestureSettingsPen: {\n scrollToZoom: false,\n clickToZoom: true,\n dblClickToZoom: false,\n pinchToZoom: false,\n flickEnabled: false,\n flickMinSpeed: 120,\n flickMomentum: 0.25,\n pinchRotate: false\n },\n gestureSettingsUnknown: {\n scrollToZoom: false,\n clickToZoom: false,\n dblClickToZoom: true,\n pinchToZoom: true,\n flickEnabled: true,\n flickMinSpeed: 120,\n flickMomentum: 0.25,\n pinchRotate: false\n },\n zoomPerClick: 2,\n zoomPerScroll: 1.2,\n zoomPerSecond: 1.0,\n blendTime: 0,\n alwaysBlend: false,\n autoHideControls: true,\n immediateRender: false,\n minZoomImageRatio: 0.9, //-> closer to 0 allows zoom out to infinity\n maxZoomPixelRatio: 1.1, //-> higher allows 'over zoom' into pixels\n smoothTileEdgesMinZoom: 1.1, //-> higher than maxZoomPixelRatio disables it\n iOSDevice: isIOSDevice(),\n pixelsPerWheelLine: 40,\n autoResize: true,\n preserveImageSizeOnResize: false, // requires autoResize=true\n minScrollDeltaTime: 50,\n\n //DEFAULT CONTROL SETTINGS\n showSequenceControl: true, //SEQUENCE\n sequenceControlAnchor: null, //SEQUENCE\n preserveViewport: false, //SEQUENCE\n preserveOverlays: false, //SEQUENCE\n navPrevNextWrap: false, //SEQUENCE\n showNavigationControl: true, //ZOOM/HOME/FULL/ROTATION\n navigationControlAnchor: null, //ZOOM/HOME/FULL/ROTATION\n showZoomControl: true, //ZOOM\n showHomeControl: true, //HOME\n showFullPageControl: true, //FULL\n showRotationControl: false, //ROTATION\n controlsFadeDelay: 2000, //ZOOM/HOME/FULL/SEQUENCE\n controlsFadeLength: 1500, //ZOOM/HOME/FULL/SEQUENCE\n mouseNavEnabled: true, //GENERAL MOUSE INTERACTIVITY\n\n //VIEWPORT NAVIGATOR SETTINGS\n showNavigator: false,\n navigatorId: null,\n navigatorPosition: null,\n navigatorSizeRatio: 0.2,\n navigatorMaintainSizeRatio: false,\n navigatorTop: null,\n navigatorLeft: null,\n navigatorHeight: null,\n navigatorWidth: null,\n navigatorAutoResize: true,\n navigatorAutoFade: true,\n navigatorRotate: true,\n\n // INITIAL ROTATION\n degrees: 0,\n\n // APPEARANCE\n opacity: 1,\n preload: false,\n compositeOperation: null,\n placeholderFillStyle: null,\n\n //REFERENCE STRIP SETTINGS\n showReferenceStrip: false,\n referenceStripScroll: 'horizontal',\n referenceStripElement: null,\n referenceStripHeight: null,\n referenceStripWidth: null,\n referenceStripPosition: 'BOTTOM_LEFT',\n referenceStripSizeRatio: 0.2,\n\n //COLLECTION VISUALIZATION SETTINGS\n collectionRows: 3, //or columns depending on layout\n collectionColumns: 0, //columns in horizontal layout, rows in vertical layout\n collectionLayout: 'horizontal', //vertical\n collectionMode: false,\n collectionTileSize: 800,\n collectionTileMargin: 80,\n\n //PERFORMANCE SETTINGS\n imageLoaderLimit: 0,\n maxImageCacheCount: 200,\n timeout: 30000,\n useCanvas: true, // Use canvas element for drawing if available\n\n //INTERFACE RESOURCE SETTINGS\n prefixUrl: \"/images/\",\n navImages: {\n zoomIn: {\n REST: 'zoomin_rest.png',\n GROUP: 'zoomin_grouphover.png',\n HOVER: 'zoomin_hover.png',\n DOWN: 'zoomin_pressed.png'\n },\n zoomOut: {\n REST: 'zoomout_rest.png',\n GROUP: 'zoomout_grouphover.png',\n HOVER: 'zoomout_hover.png',\n DOWN: 'zoomout_pressed.png'\n },\n home: {\n REST: 'home_rest.png',\n GROUP: 'home_grouphover.png',\n HOVER: 'home_hover.png',\n DOWN: 'home_pressed.png'\n },\n fullpage: {\n REST: 'fullpage_rest.png',\n GROUP: 'fullpage_grouphover.png',\n HOVER: 'fullpage_hover.png',\n DOWN: 'fullpage_pressed.png'\n },\n rotateleft: {\n REST: 'rotateleft_rest.png',\n GROUP: 'rotateleft_grouphover.png',\n HOVER: 'rotateleft_hover.png',\n DOWN: 'rotateleft_pressed.png'\n },\n rotateright: {\n REST: 'rotateright_rest.png',\n GROUP: 'rotateright_grouphover.png',\n HOVER: 'rotateright_hover.png',\n DOWN: 'rotateright_pressed.png'\n },\n previous: {\n REST: 'previous_rest.png',\n GROUP: 'previous_grouphover.png',\n HOVER: 'previous_hover.png',\n DOWN: 'previous_pressed.png'\n },\n next: {\n REST: 'next_rest.png',\n GROUP: 'next_grouphover.png',\n HOVER: 'next_hover.png',\n DOWN: 'next_pressed.png'\n }\n },\n\n //DEVELOPER SETTINGS\n debugMode: false,\n debugGridColor: ['#437AB2', '#1B9E77', '#D95F02', '#7570B3', '#E7298A', '#66A61E', '#E6AB02', '#A6761D', '#666666']\n },\n\n\n /**\n * TODO: get rid of this. I can't see how it's required at all. Looks\n * like an early legacy code artifact.\n * @static\n * @ignore\n */\n SIGNAL: \"----seadragon----\",\n\n\n /**\n * Returns a function which invokes the method as if it were a method belonging to the object.\n * @function\n * @param {Object} object\n * @param {Function} method\n * @returns {Function}\n */\n delegate: function( object, method ) {\n return function(){\n var args = arguments;\n if ( args === undefined ){\n args = [];\n }\n return method.apply( object, args );\n };\n },\n\n\n /**\n * An enumeration of Browser vendors.\n * @static\n * @type {Object}\n * @property {Number} UNKNOWN\n * @property {Number} IE\n * @property {Number} FIREFOX\n * @property {Number} SAFARI\n * @property {Number} CHROME\n * @property {Number} OPERA\n */\n BROWSERS: {\n UNKNOWN: 0,\n IE: 1,\n FIREFOX: 2,\n SAFARI: 3,\n CHROME: 4,\n OPERA: 5\n },\n\n\n /**\n * Returns a DOM Element for the given id or element.\n * @function\n * @param {String|Element} element Accepts an id or element.\n * @returns {Element} The element with the given id, null, or the element itself.\n */\n getElement: function( element ) {\n if ( typeof ( element ) == \"string\" ) {\n element = document.getElementById( element );\n }\n return element;\n },\n\n\n /**\n * Determines the position of the upper-left corner of the element.\n * @function\n * @param {Element|String} element - the elemenet we want the position for.\n * @returns {OpenSeadragon.Point} - the position of the upper left corner of the element.\n */\n getElementPosition: function( element ) {\n var result = new $.Point(),\n isFixed,\n offsetParent;\n\n element = $.getElement( element );\n isFixed = $.getElementStyle( element ).position == \"fixed\";\n offsetParent = getOffsetParent( element, isFixed );\n\n while ( offsetParent ) {\n\n result.x += element.offsetLeft;\n result.y += element.offsetTop;\n\n if ( isFixed ) {\n result = result.plus( $.getPageScroll() );\n }\n\n element = offsetParent;\n isFixed = $.getElementStyle( element ).position == \"fixed\";\n offsetParent = getOffsetParent( element, isFixed );\n }\n\n return result;\n },\n\n\n /**\n * Determines the position of the upper-left corner of the element adjusted for current page and/or element scroll.\n * @function\n * @param {Element|String} element - the element we want the position for.\n * @returns {OpenSeadragon.Point} - the position of the upper left corner of the element adjusted for current page and/or element scroll.\n */\n getElementOffset: function( element ) {\n element = $.getElement( element );\n\n var doc = element && element.ownerDocument,\n docElement,\n win,\n boundingRect = { top: 0, left: 0 };\n\n if ( !doc ) {\n return new $.Point();\n }\n\n docElement = doc.documentElement;\n\n if ( typeof element.getBoundingClientRect !== typeof undefined ) {\n boundingRect = element.getBoundingClientRect();\n }\n\n win = ( doc == doc.window ) ?\n doc :\n ( doc.nodeType === 9 ) ?\n doc.defaultView || doc.parentWindow :\n false;\n\n return new $.Point(\n boundingRect.left + ( win.pageXOffset || docElement.scrollLeft ) - ( docElement.clientLeft || 0 ),\n boundingRect.top + ( win.pageYOffset || docElement.scrollTop ) - ( docElement.clientTop || 0 )\n );\n },\n\n\n /**\n * Determines the height and width of the given element.\n * @function\n * @param {Element|String} element\n * @returns {OpenSeadragon.Point}\n */\n getElementSize: function( element ) {\n element = $.getElement( element );\n\n return new $.Point(\n element.clientWidth,\n element.clientHeight\n );\n },\n\n\n /**\n * Returns the CSSStyle object for the given element.\n * @function\n * @param {Element|String} element\n * @returns {CSSStyle}\n */\n getElementStyle:\n document.documentElement.currentStyle ?\n function( element ) {\n element = $.getElement( element );\n return element.currentStyle;\n } :\n function( element ) {\n element = $.getElement( element );\n return window.getComputedStyle( element, \"\" );\n },\n\n /**\n * Returns the property with the correct vendor prefix appended.\n * @param {String} property the property name\n * @returns {String} the property with the correct prefix or null if not\n * supported.\n */\n getCssPropertyWithVendorPrefix: function(property) {\n var memo = {};\n\n $.getCssPropertyWithVendorPrefix = function(property) {\n if (memo[property] !== undefined) {\n return memo[property];\n }\n var style = document.createElement('div').style;\n var result = null;\n if (style[property] !== undefined) {\n result = property;\n } else {\n var prefixes = ['Webkit', 'Moz', 'MS', 'O',\n 'webkit', 'moz', 'ms', 'o'];\n var suffix = $.capitalizeFirstLetter(property);\n for (var i = 0; i < prefixes.length; i++) {\n var prop = prefixes[i] + suffix;\n if (style[prop] !== undefined) {\n result = prop;\n break;\n }\n }\n }\n memo[property] = result;\n return result;\n };\n return $.getCssPropertyWithVendorPrefix(property);\n },\n\n /**\n * Capitalizes the first letter of a string\n * @param {String} string\n * @returns {String} The string with the first letter capitalized\n */\n capitalizeFirstLetter: function(string) {\n return string.charAt(0).toUpperCase() + string.slice(1);\n },\n\n /**\n * Compute the modulo of a number but makes sure to always return\n * a positive value.\n * @param {Number} number the number to computes the modulo of\n * @param {Number} modulo the modulo\n * @returns {Number} the result of the modulo of number\n */\n positiveModulo: function(number, modulo) {\n var result = number % modulo;\n if (result < 0) {\n result += modulo;\n }\n return result;\n },\n\n /**\n * Determines if a point is within the bounding rectangle of the given element (hit-test).\n * @function\n * @param {Element|String} element\n * @param {OpenSeadragon.Point} point\n * @returns {Boolean}\n */\n pointInElement: function( element, point ) {\n element = $.getElement( element );\n var offset = $.getElementOffset( element ),\n size = $.getElementSize( element );\n return point.x >= offset.x && point.x < offset.x + size.x && point.y < offset.y + size.y && point.y >= offset.y;\n },\n\n\n /**\n * Gets the latest event, really only useful internally since its\n * specific to IE behavior.\n * @function\n * @param {Event} [event]\n * @returns {Event}\n * @deprecated For internal use only\n * @private\n */\n getEvent: function( event ) {\n if( event ){\n $.getEvent = function( event ) {\n return event;\n };\n } else {\n $.getEvent = function() {\n return window.event;\n };\n }\n return $.getEvent( event );\n },\n\n\n /**\n * Gets the position of the mouse on the screen for a given event.\n * @function\n * @param {Event} [event]\n * @returns {OpenSeadragon.Point}\n */\n getMousePosition: function( event ) {\n\n if ( typeof( event.pageX ) == \"number\" ) {\n $.getMousePosition = function( event ){\n var result = new $.Point();\n\n event = $.getEvent( event );\n result.x = event.pageX;\n result.y = event.pageY;\n\n return result;\n };\n } else if ( typeof( event.clientX ) == \"number\" ) {\n $.getMousePosition = function( event ){\n var result = new $.Point();\n\n event = $.getEvent( event );\n result.x =\n event.clientX +\n document.body.scrollLeft +\n document.documentElement.scrollLeft;\n result.y =\n event.clientY +\n document.body.scrollTop +\n document.documentElement.scrollTop;\n\n return result;\n };\n } else {\n throw new Error(\n \"Unknown event mouse position, no known technique.\"\n );\n }\n\n return $.getMousePosition( event );\n },\n\n\n /**\n * Determines the page's current scroll position.\n * @function\n * @returns {OpenSeadragon.Point}\n */\n getPageScroll: function() {\n var docElement = document.documentElement || {},\n body = document.body || {};\n\n if ( typeof( window.pageXOffset ) == \"number\" ) {\n $.getPageScroll = function(){\n return new $.Point(\n window.pageXOffset,\n window.pageYOffset\n );\n };\n } else if ( body.scrollLeft || body.scrollTop ) {\n $.getPageScroll = function(){\n return new $.Point(\n document.body.scrollLeft,\n document.body.scrollTop\n );\n };\n } else if ( docElement.scrollLeft || docElement.scrollTop ) {\n $.getPageScroll = function(){\n return new $.Point(\n document.documentElement.scrollLeft,\n document.documentElement.scrollTop\n );\n };\n } else {\n // We can't reassign the function yet, as there was no scroll.\n return new $.Point(0, 0);\n }\n\n return $.getPageScroll();\n },\n\n /**\n * Set the page scroll position.\n * @function\n * @returns {OpenSeadragon.Point}\n */\n setPageScroll: function( scroll ) {\n if ( typeof ( window.scrollTo ) !== \"undefined\" ) {\n $.setPageScroll = function( scroll ) {\n window.scrollTo( scroll.x, scroll.y );\n };\n } else {\n var originalScroll = $.getPageScroll();\n if ( originalScroll.x === scroll.x &&\n originalScroll.y === scroll.y ) {\n // We are already correctly positioned and there\n // is no way to detect the correct method.\n return;\n }\n\n document.body.scrollLeft = scroll.x;\n document.body.scrollTop = scroll.y;\n var currentScroll = $.getPageScroll();\n if ( currentScroll.x !== originalScroll.x &&\n currentScroll.y !== originalScroll.y ) {\n $.setPageScroll = function( scroll ) {\n document.body.scrollLeft = scroll.x;\n document.body.scrollTop = scroll.y;\n };\n return;\n }\n\n document.documentElement.scrollLeft = scroll.x;\n document.documentElement.scrollTop = scroll.y;\n currentScroll = $.getPageScroll();\n if ( currentScroll.x !== originalScroll.x &&\n currentScroll.y !== originalScroll.y ) {\n $.setPageScroll = function( scroll ) {\n document.documentElement.scrollLeft = scroll.x;\n document.documentElement.scrollTop = scroll.y;\n };\n return;\n }\n\n // We can't find anything working, so we do nothing.\n $.setPageScroll = function( scroll ) {\n };\n }\n\n return $.setPageScroll( scroll );\n },\n\n /**\n * Determines the size of the browsers window.\n * @function\n * @returns {OpenSeadragon.Point}\n */\n getWindowSize: function() {\n var docElement = document.documentElement || {},\n body = document.body || {};\n\n if ( typeof( window.innerWidth ) == 'number' ) {\n $.getWindowSize = function(){\n return new $.Point(\n window.innerWidth,\n window.innerHeight\n );\n };\n } else if ( docElement.clientWidth || docElement.clientHeight ) {\n $.getWindowSize = function(){\n return new $.Point(\n document.documentElement.clientWidth,\n document.documentElement.clientHeight\n );\n };\n } else if ( body.clientWidth || body.clientHeight ) {\n $.getWindowSize = function(){\n return new $.Point(\n document.body.clientWidth,\n document.body.clientHeight\n );\n };\n } else {\n throw new Error(\"Unknown window size, no known technique.\");\n }\n\n return $.getWindowSize();\n },\n\n\n /**\n * Wraps the given element in a nest of divs so that the element can\n * be easily centered using CSS tables\n * @function\n * @param {Element|String} element\n * @returns {Element} outermost wrapper element\n */\n makeCenteredNode: function( element ) {\n // Convert a possible ID to an actual HTMLElement\n element = $.getElement( element );\n\n /*\n CSS tables require you to have a display:table/row/cell hierarchy so we need to create\n three nested wrapper divs:\n */\n\n var wrappers = [\n $.makeNeutralElement( 'div' ),\n $.makeNeutralElement( 'div' ),\n $.makeNeutralElement( 'div' )\n ];\n\n // It feels like we should be able to pass style dicts to makeNeutralElement:\n $.extend(wrappers[0].style, {\n display: \"table\",\n height: \"100%\",\n width: \"100%\"\n });\n\n $.extend(wrappers[1].style, {\n display: \"table-row\"\n });\n\n $.extend(wrappers[2].style, {\n display: \"table-cell\",\n verticalAlign: \"middle\",\n textAlign: \"center\"\n });\n\n wrappers[0].appendChild(wrappers[1]);\n wrappers[1].appendChild(wrappers[2]);\n wrappers[2].appendChild(element);\n\n return wrappers[0];\n },\n\n\n /**\n * Creates an easily positionable element of the given type that therefor\n * serves as an excellent container element.\n * @function\n * @param {String} tagName\n * @returns {Element}\n */\n makeNeutralElement: function( tagName ) {\n var element = document.createElement( tagName ),\n style = element.style;\n\n style.background = \"transparent none\";\n style.border = \"none\";\n style.margin = \"0px\";\n style.padding = \"0px\";\n style.position = \"static\";\n\n return element;\n },\n\n\n /**\n * Returns the current milliseconds, using Date.now() if available\n * @function\n */\n now: function( ) {\n if (Date.now) {\n $.now = Date.now;\n } else {\n $.now = function() {\n return new Date().getTime();\n };\n }\n\n return $.now();\n },\n\n\n /**\n * Ensures an image is loaded correctly to support alpha transparency.\n * Generally only IE has issues doing this correctly for formats like\n * png.\n * @function\n * @param {String} src\n * @returns {Element}\n */\n makeTransparentImage: function( src ) {\n\n $.makeTransparentImage = function( src ){\n var img = $.makeNeutralElement( \"img\" );\n\n img.src = src;\n\n return img;\n };\n\n if ( $.Browser.vendor == $.BROWSERS.IE && $.Browser.version < 7 ) {\n\n $.makeTransparentImage = function( src ){\n var img = $.makeNeutralElement( \"img\" ),\n element = null;\n\n element = $.makeNeutralElement(\"span\");\n element.style.display = \"inline-block\";\n\n img.onload = function() {\n element.style.width = element.style.width || img.width + \"px\";\n element.style.height = element.style.height || img.height + \"px\";\n\n img.onload = null;\n img = null; // to prevent memory leaks in IE\n };\n\n img.src = src;\n element.style.filter =\n \"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='\" +\n src +\n \"', sizingMethod='scale')\";\n\n return element;\n };\n\n }\n\n return $.makeTransparentImage( src );\n },\n\n\n /**\n * Sets the opacity of the specified element.\n * @function\n * @param {Element|String} element\n * @param {Number} opacity\n * @param {Boolean} [usesAlpha]\n */\n setElementOpacity: function( element, opacity, usesAlpha ) {\n\n var ieOpacity,\n ieFilter;\n\n element = $.getElement( element );\n\n if ( usesAlpha && !$.Browser.alpha ) {\n opacity = Math.round( opacity );\n }\n\n if ( $.Browser.opacity ) {\n element.style.opacity = opacity < 1 ? opacity : \"\";\n } else {\n if ( opacity < 1 ) {\n ieOpacity = Math.round( 100 * opacity );\n ieFilter = \"alpha(opacity=\" + ieOpacity + \")\";\n element.style.filter = ieFilter;\n } else {\n element.style.filter = \"\";\n }\n }\n },\n\n\n /**\n * Sets the specified element's touch-action style attribute to 'none'.\n * @function\n * @param {Element|String} element\n */\n setElementTouchActionNone: function( element ) {\n element = $.getElement( element );\n if ( typeof element.style.touchAction !== 'undefined' ) {\n element.style.touchAction = 'none';\n } else if ( typeof element.style.msTouchAction !== 'undefined' ) {\n element.style.msTouchAction = 'none';\n }\n },\n\n\n /**\n * Add the specified CSS class to the element if not present.\n * @function\n * @param {Element|String} element\n * @param {String} className\n */\n addClass: function( element, className ) {\n element = $.getElement( element );\n\n if (!element.className) {\n element.className = className;\n } else if ( ( ' ' + element.className + ' ' ).\n indexOf( ' ' + className + ' ' ) === -1 ) {\n element.className += ' ' + className;\n }\n },\n\n /**\n * Find the first index at which an element is found in an array or -1\n * if not present.\n *\n * Code taken and adapted from\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf#Compatibility\n *\n * @function\n * @param {Array} array The array from which to find the element\n * @param {Object} searchElement The element to find\n * @param {Number} [fromIndex=0] Index to start research.\n * @returns {Number} The index of the element in the array.\n */\n indexOf: function( array, searchElement, fromIndex ) {\n if ( Array.prototype.indexOf ) {\n this.indexOf = function( array, searchElement, fromIndex ) {\n return array.indexOf( searchElement, fromIndex );\n };\n } else {\n this.indexOf = function( array, searchElement, fromIndex ) {\n var i,\n pivot = ( fromIndex ) ? fromIndex : 0,\n length;\n if ( !array ) {\n throw new TypeError( );\n }\n\n length = array.length;\n if ( length === 0 || pivot >= length ) {\n return -1;\n }\n\n if ( pivot < 0 ) {\n pivot = length - Math.abs( pivot );\n }\n\n for ( i = pivot; i < length; i++ ) {\n if ( array[i] === searchElement ) {\n return i;\n }\n }\n return -1;\n };\n }\n return this.indexOf( array, searchElement, fromIndex );\n },\n\n /**\n * Remove the specified CSS class from the element.\n * @function\n * @param {Element|String} element\n * @param {String} className\n */\n removeClass: function( element, className ) {\n var oldClasses,\n newClasses = [],\n i;\n\n element = $.getElement( element );\n oldClasses = element.className.split( /\\s+/ );\n for ( i = 0; i < oldClasses.length; i++ ) {\n if ( oldClasses[ i ] && oldClasses[ i ] !== className ) {\n newClasses.push( oldClasses[ i ] );\n }\n }\n element.className = newClasses.join(' ');\n },\n\n\n /**\n * Adds an event listener for the given element, eventName and handler.\n * @function\n * @param {Element|String} element\n * @param {String} eventName\n * @param {Function} handler\n * @param {Boolean} [useCapture]\n */\n addEvent: (function () {\n if ( window.addEventListener ) {\n return function ( element, eventName, handler, useCapture ) {\n element = $.getElement( element );\n element.addEventListener( eventName, handler, useCapture );\n };\n } else if ( window.attachEvent ) {\n return function ( element, eventName, handler, useCapture ) {\n element = $.getElement( element );\n element.attachEvent( 'on' + eventName, handler );\n };\n } else {\n throw new Error( \"No known event model.\" );\n }\n }()),\n\n\n /**\n * Remove a given event listener for the given element, event type and\n * handler.\n * @function\n * @param {Element|String} element\n * @param {String} eventName\n * @param {Function} handler\n * @param {Boolean} [useCapture]\n */\n removeEvent: (function () {\n if ( window.removeEventListener ) {\n return function ( element, eventName, handler, useCapture ) {\n element = $.getElement( element );\n element.removeEventListener( eventName, handler, useCapture );\n };\n } else if ( window.detachEvent ) {\n return function( element, eventName, handler, useCapture ) {\n element = $.getElement( element );\n element.detachEvent( 'on' + eventName, handler );\n };\n } else {\n throw new Error( \"No known event model.\" );\n }\n }()),\n\n\n /**\n * Cancels the default browser behavior had the event propagated all\n * the way up the DOM to the window object.\n * @function\n * @param {Event} [event]\n */\n cancelEvent: function( event ) {\n event = $.getEvent( event );\n\n if ( event.preventDefault ) {\n $.cancelEvent = function( event ){\n // W3C for preventing default\n event.preventDefault();\n };\n } else {\n $.cancelEvent = function( event ){\n event = $.getEvent( event );\n // legacy for preventing default\n event.cancel = true;\n // IE for preventing default\n event.returnValue = false;\n };\n }\n $.cancelEvent( event );\n },\n\n\n /**\n * Stops the propagation of the event up the DOM.\n * @function\n * @param {Event} [event]\n */\n stopEvent: function( event ) {\n event = $.getEvent( event );\n\n if ( event.stopPropagation ) {\n // W3C for stopping propagation\n $.stopEvent = function( event ){\n event.stopPropagation();\n };\n } else {\n // IE for stopping propagation\n $.stopEvent = function( event ){\n event = $.getEvent( event );\n event.cancelBubble = true;\n };\n\n }\n\n $.stopEvent( event );\n },\n\n\n /**\n * Similar to OpenSeadragon.delegate, but it does not immediately call\n * the method on the object, returning a function which can be called\n * repeatedly to delegate the method. It also allows additonal arguments\n * to be passed during construction which will be added during each\n * invocation, and each invocation can add additional arguments as well.\n *\n * @function\n * @param {Object} object\n * @param {Function} method\n * @param [args] any additional arguments are passed as arguments to the\n * created callback\n * @returns {Function}\n */\n createCallback: function( object, method ) {\n //TODO: This pattern is painful to use and debug. It's much cleaner\n // to use pinning plus anonymous functions. Get rid of this\n // pattern!\n var initialArgs = [],\n i;\n for ( i = 2; i < arguments.length; i++ ) {\n initialArgs.push( arguments[ i ] );\n }\n\n return function() {\n var args = initialArgs.concat( [] ),\n i;\n for ( i = 0; i < arguments.length; i++ ) {\n args.push( arguments[ i ] );\n }\n\n return method.apply( object, args );\n };\n },\n\n\n /**\n * Retreives the value of a url parameter from the window.location string.\n * @function\n * @param {String} key\n * @returns {String} The value of the url parameter or null if no param matches.\n */\n getUrlParameter: function( key ) {\n // eslint-disable-next-line no-use-before-define\n var value = URLPARAMS[ key ];\n return value ? value : null;\n },\n\n /**\n * Retrieves the protocol used by the url. The url can either be absolute\n * or relative.\n * @function\n * @private\n * @param {String} url The url to retrieve the protocol from.\n * @return {String} The protocol (http:, https:, file:, ftp: ...)\n */\n getUrlProtocol: function( url ) {\n var match = url.match(/^([a-z]+:)\\/\\//i);\n if ( match === null ) {\n // Relative URL, retrive the protocol from window.location\n return window.location.protocol;\n }\n return match[1].toLowerCase();\n },\n\n /**\n * Create an XHR object\n * @private\n * @param {type} [local] If set to true, the XHR will be file: protocol\n * compatible if possible (but may raise a warning in the browser).\n * @returns {XMLHttpRequest}\n */\n createAjaxRequest: function( local ) {\n // IE11 does not support window.ActiveXObject so we just try to\n // create one to see if it is supported.\n // See: http://msdn.microsoft.com/en-us/library/ie/dn423948%28v=vs.85%29.aspx\n var supportActiveX;\n try {\n /* global ActiveXObject:true */\n supportActiveX = !!new ActiveXObject( \"Microsoft.XMLHTTP\" );\n } catch( e ) {\n supportActiveX = false;\n }\n\n if ( supportActiveX ) {\n if ( window.XMLHttpRequest ) {\n $.createAjaxRequest = function( local ) {\n if ( local ) {\n return new ActiveXObject( \"Microsoft.XMLHTTP\" );\n }\n return new XMLHttpRequest();\n };\n } else {\n $.createAjaxRequest = function() {\n return new ActiveXObject( \"Microsoft.XMLHTTP\" );\n };\n }\n } else if ( window.XMLHttpRequest ) {\n $.createAjaxRequest = function() {\n return new XMLHttpRequest();\n };\n } else {\n throw new Error( \"Browser doesn't support XMLHttpRequest.\" );\n }\n return $.createAjaxRequest( local );\n },\n\n /**\n * Makes an AJAX request.\n * @param {Object} options\n * @param {String} options.url - the url to request\n * @param {Function} options.success - a function to call on a successful response\n * @param {Function} options.error - a function to call on when an error occurs\n * @param {Object} options.headers - headers to add to the AJAX request\n * @param {String} options.responseType - the response type of the the AJAX request\n * @param {Boolean} [options.withCredentials=false] - whether to set the XHR's withCredentials\n * @throws {Error}\n * @returns {XMLHttpRequest}\n */\n makeAjaxRequest: function( url, onSuccess, onError ) {\n var withCredentials;\n var headers;\n var responseType;\n\n // Note that our preferred API is that you pass in a single object; the named\n // arguments are for legacy support.\n if( $.isPlainObject( url ) ){\n onSuccess = url.success;\n onError = url.error;\n withCredentials = url.withCredentials;\n headers = url.headers;\n responseType = url.responseType || null;\n url = url.url;\n }\n\n var protocol = $.getUrlProtocol( url );\n var request = $.createAjaxRequest( protocol === \"file:\" );\n\n if ( !$.isFunction( onSuccess ) ) {\n throw new Error( \"makeAjaxRequest requires a success callback\" );\n }\n\n request.onreadystatechange = function() {\n // 4 = DONE (https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#Properties)\n if ( request.readyState == 4 ) {\n request.onreadystatechange = function(){};\n\n // With protocols other than http/https, a successful request status is in\n // the 200's on Firefox and 0 on other browsers\n if ( (request.status >= 200 && request.status < 300) ||\n ( request.status === 0 &&\n protocol !== \"http:\" &&\n protocol !== \"https:\" )) {\n onSuccess( request );\n } else {\n $.console.log( \"AJAX request returned %d: %s\", request.status, url );\n\n if ( $.isFunction( onError ) ) {\n onError( request );\n }\n }\n }\n };\n\n try {\n request.open( \"GET\", url, true );\n\n if (responseType) {\n request.responseType = responseType;\n }\n\n if (headers) {\n for (var headerName in headers) {\n if (headers.hasOwnProperty(headerName) && headers[headerName]) {\n request.setRequestHeader(headerName, headers[headerName]);\n }\n }\n }\n\n if (withCredentials) {\n request.withCredentials = true;\n }\n\n request.send(null);\n } catch (e) {\n var msg = e.message;\n\n /*\n IE < 10 does not support CORS and an XHR request to a different origin will fail as soon\n as send() is called. This is particularly easy to miss during development and appear in\n production if you use a CDN or domain sharding and the security policy is likely to break\n exception handlers since any attempt to access a property of the request object will\n raise an access denied TypeError inside the catch block.\n\n To be friendlier, we'll check for this specific error and add a documentation pointer\n to point developers in the right direction. We test the exception number because IE's\n error messages are localized.\n */\n var oldIE = $.Browser.vendor == $.BROWSERS.IE && $.Browser.version < 10;\n if ( oldIE && typeof( e.number ) != \"undefined\" && e.number == -2147024891 ) {\n msg += \"\\nSee http://msdn.microsoft.com/en-us/library/ms537505(v=vs.85).aspx#xdomain\";\n }\n\n $.console.log( \"%s while making AJAX request: %s\", e.name, msg );\n\n request.onreadystatechange = function(){};\n\n if (window.XDomainRequest) { // IE9 or IE8 might as well try to use XDomainRequest\n var xdr = new XDomainRequest();\n if (xdr) {\n xdr.onload = function (e) {\n if ( $.isFunction( onSuccess ) ) {\n onSuccess({ // Faking an xhr object\n responseText: xdr.responseText,\n status: 200, // XDomainRequest doesn't support status codes, so we just fake one! :/\n statusText: 'OK'\n });\n }\n };\n xdr.onerror = function (e) {\n if ($.isFunction(onError)) {\n onError({ // Faking an xhr object\n responseText: xdr.responseText,\n status: 444, // 444 No Response\n statusText: 'An error happened. Due to an XDomainRequest deficiency we can not extract any information about this error. Upgrade your browser.'\n });\n }\n };\n try {\n xdr.open('GET', url);\n xdr.send();\n } catch (e2) {\n if ( $.isFunction( onError ) ) {\n onError( request, e );\n }\n }\n }\n } else {\n if ( $.isFunction( onError ) ) {\n onError( request, e );\n }\n }\n }\n\n return request;\n },\n\n /**\n * Taken from jQuery 1.6.1\n * @function\n * @param {Object} options\n * @param {String} options.url\n * @param {Function} options.callback\n * @param {String} [options.param='callback'] The name of the url parameter\n * to request the jsonp provider with.\n * @param {String} [options.callbackName=] The name of the callback to\n * request the jsonp provider with.\n */\n jsonp: function( options ){\n var script,\n url = options.url,\n head = document.head ||\n document.getElementsByTagName( \"head\" )[ 0 ] ||\n document.documentElement,\n jsonpCallback = options.callbackName || 'openseadragon' + $.now(),\n previous = window[ jsonpCallback ],\n replace = \"$1\" + jsonpCallback + \"$2\",\n callbackParam = options.param || 'callback',\n callback = options.callback;\n\n url = url.replace( /(\\=)\\?(&|$)|\\?\\?/i, replace );\n // Add callback manually\n url += (/\\?/.test( url ) ? \"&\" : \"?\") + callbackParam + \"=\" + jsonpCallback;\n\n // Install callback\n window[ jsonpCallback ] = function( response ) {\n if ( !previous ){\n try{\n delete window[ jsonpCallback ];\n }catch(e){\n //swallow\n }\n } else {\n window[ jsonpCallback ] = previous;\n }\n if( callback && $.isFunction( callback ) ){\n callback( response );\n }\n };\n\n script = document.createElement( \"script\" );\n\n //TODO: having an issue with async info requests\n if( undefined !== options.async || false !== options.async ){\n script.async = \"async\";\n }\n\n if ( options.scriptCharset ) {\n script.charset = options.scriptCharset;\n }\n\n script.src = url;\n\n // Attach handlers for all browsers\n script.onload = script.onreadystatechange = function( _, isAbort ) {\n\n if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {\n\n // Handle memory leak in IE\n script.onload = script.onreadystatechange = null;\n\n // Remove the script\n if ( head && script.parentNode ) {\n head.removeChild( script );\n }\n\n // Dereference the script\n script = undefined;\n }\n };\n // Use insertBefore instead of appendChild to circumvent an IE6 bug.\n // This arises when a base node is used (#2709 and #4378).\n head.insertBefore( script, head.firstChild );\n\n },\n\n\n /**\n * Fully deprecated. Will throw an error.\n * @function\n * @deprecated use {@link OpenSeadragon.Viewer#open}\n */\n createFromDZI: function() {\n throw \"OpenSeadragon.createFromDZI is deprecated, use Viewer.open.\";\n },\n\n /**\n * Parses an XML string into a DOM Document.\n * @function\n * @param {String} string\n * @returns {Document}\n */\n parseXml: function( string ) {\n if ( window.DOMParser ) {\n\n $.parseXml = function( string ) {\n var xmlDoc = null,\n parser;\n\n parser = new DOMParser();\n xmlDoc = parser.parseFromString( string, \"text/xml\" );\n return xmlDoc;\n };\n\n } else if ( window.ActiveXObject ) {\n\n $.parseXml = function( string ) {\n var xmlDoc = null;\n\n xmlDoc = new ActiveXObject( \"Microsoft.XMLDOM\" );\n xmlDoc.async = false;\n xmlDoc.loadXML( string );\n return xmlDoc;\n };\n\n } else {\n throw new Error( \"Browser doesn't support XML DOM.\" );\n }\n\n return $.parseXml( string );\n },\n\n /**\n * Parses a JSON string into a Javascript object.\n * @function\n * @param {String} string\n * @returns {Object}\n */\n parseJSON: function(string) {\n if (window.JSON && window.JSON.parse) {\n $.parseJSON = window.JSON.parse;\n } else {\n // Should only be used by IE8 in non standards mode\n $.parseJSON = function(string) {\n /*jshint evil:true*/\n //eslint-disable-next-line no-eval\n return eval('(' + string + ')');\n };\n }\n return $.parseJSON(string);\n },\n\n /**\n * Reports whether the image format is supported for tiling in this\n * version.\n * @function\n * @param {String} [extension]\n * @returns {Boolean}\n */\n imageFormatSupported: function( extension ) {\n extension = extension ? extension : \"\";\n // eslint-disable-next-line no-use-before-define\n return !!FILEFORMATS[ extension.toLowerCase() ];\n }\n\n });\n\n\n /**\n * The current browser vendor, version, and related information regarding detected features.\n * @member {Object} Browser\n * @memberof OpenSeadragon\n * @static\n * @type {Object}\n * @property {OpenSeadragon.BROWSERS} vendor - One of the {@link OpenSeadragon.BROWSERS} enumeration values.\n * @property {Number} version\n * @property {Boolean} alpha - Does the browser support image alpha transparency.\n */\n $.Browser = {\n vendor: $.BROWSERS.UNKNOWN,\n version: 0,\n alpha: true\n };\n\n\n var FILEFORMATS = {\n \"bmp\": false,\n \"jpeg\": true,\n \"jpg\": true,\n \"png\": true,\n \"tif\": false,\n \"wdp\": false\n },\n URLPARAMS = {};\n\n (function() {\n //A small auto-executing routine to determine the browser vendor,\n //version and supporting feature sets.\n var ver = navigator.appVersion,\n ua = navigator.userAgent,\n regex;\n\n //console.error( 'appName: ' + navigator.appName );\n //console.error( 'appVersion: ' + navigator.appVersion );\n //console.error( 'userAgent: ' + navigator.userAgent );\n\n switch( navigator.appName ){\n case \"Microsoft Internet Explorer\":\n if( !!window.attachEvent &&\n !!window.ActiveXObject ) {\n\n $.Browser.vendor = $.BROWSERS.IE;\n $.Browser.version = parseFloat(\n ua.substring(\n ua.indexOf( \"MSIE\" ) + 5,\n ua.indexOf( \";\", ua.indexOf( \"MSIE\" ) ) )\n );\n }\n break;\n case \"Netscape\":\n if (window.addEventListener) {\n if ( ua.indexOf( \"Firefox\" ) >= 0 ) {\n $.Browser.vendor = $.BROWSERS.FIREFOX;\n $.Browser.version = parseFloat(\n ua.substring( ua.indexOf( \"Firefox\" ) + 8 )\n );\n } else if ( ua.indexOf( \"Safari\" ) >= 0 ) {\n $.Browser.vendor = ua.indexOf( \"Chrome\" ) >= 0 ?\n $.BROWSERS.CHROME :\n $.BROWSERS.SAFARI;\n $.Browser.version = parseFloat(\n ua.substring(\n ua.substring( 0, ua.indexOf( \"Safari\" ) ).lastIndexOf( \"/\" ) + 1,\n ua.indexOf( \"Safari\" )\n )\n );\n } else {\n regex = new RegExp( \"Trident/.*rv:([0-9]{1,}[.0-9]{0,})\");\n if ( regex.exec( ua ) !== null ) {\n $.Browser.vendor = $.BROWSERS.IE;\n $.Browser.version = parseFloat( RegExp.$1 );\n }\n }\n }\n break;\n case \"Opera\":\n $.Browser.vendor = $.BROWSERS.OPERA;\n $.Browser.version = parseFloat( ver );\n break;\n }\n\n // ignore '?' portion of query string\n var query = window.location.search.substring( 1 ),\n parts = query.split('&'),\n part,\n sep,\n i;\n\n for ( i = 0; i < parts.length; i++ ) {\n part = parts[ i ];\n sep = part.indexOf( '=' );\n\n if ( sep > 0 ) {\n URLPARAMS[ part.substring( 0, sep ) ] =\n decodeURIComponent( part.substring( sep + 1 ) );\n }\n }\n\n //determine if this browser supports image alpha transparency\n $.Browser.alpha = !(\n (\n $.Browser.vendor == $.BROWSERS.IE &&\n $.Browser.version < 9\n ) || (\n $.Browser.vendor == $.BROWSERS.CHROME &&\n $.Browser.version < 2\n )\n );\n\n //determine if this browser supports element.style.opacity\n $.Browser.opacity = !(\n $.Browser.vendor == $.BROWSERS.IE &&\n $.Browser.version < 9\n );\n\n })();\n\n\n //TODO: $.console is often used inside a try/catch block which generally\n // prevents allowings errors to occur with detection until a debugger\n // is attached. Although I've been guilty of the same anti-pattern\n // I eventually was convinced that errors should naturally propogate in\n // all but the most special cases.\n /**\n * A convenient alias for console when available, and a simple null\n * function when console is unavailable.\n * @static\n * @private\n */\n var nullfunction = function( msg ){\n //document.location.hash = msg;\n };\n\n $.console = window.console || {\n log: nullfunction,\n debug: nullfunction,\n info: nullfunction,\n warn: nullfunction,\n error: nullfunction,\n assert: nullfunction\n };\n\n\n // Adding support for HTML5's requestAnimationFrame as suggested by acdha.\n // Implementation taken from matt synder's post here:\n // http://mattsnider.com/cross-browser-and-legacy-supported-requestframeanimation/\n (function( w ) {\n\n // most browsers have an implementation\n var requestAnimationFrame = w.requestAnimationFrame ||\n w.mozRequestAnimationFrame ||\n w.webkitRequestAnimationFrame ||\n w.msRequestAnimationFrame;\n\n var cancelAnimationFrame = w.cancelAnimationFrame ||\n w.mozCancelAnimationFrame ||\n w.webkitCancelAnimationFrame ||\n w.msCancelAnimationFrame;\n\n // polyfill, when necessary\n if ( requestAnimationFrame && cancelAnimationFrame ) {\n // We can't assign these window methods directly to $ because they\n // expect their \"this\" to be \"window\", so we call them in wrappers.\n $.requestAnimationFrame = function(){\n return requestAnimationFrame.apply( w, arguments );\n };\n $.cancelAnimationFrame = function(){\n return cancelAnimationFrame.apply( w, arguments );\n };\n } else {\n var aAnimQueue = [],\n processing = [],\n iRequestId = 0,\n iIntervalId;\n\n // create a mock requestAnimationFrame function\n $.requestAnimationFrame = function( callback ) {\n aAnimQueue.push( [ ++iRequestId, callback ] );\n\n if ( !iIntervalId ) {\n iIntervalId = setInterval( function() {\n if ( aAnimQueue.length ) {\n var time = $.now();\n // Process all of the currently outstanding frame\n // requests, but none that get added during the\n // processing.\n // Swap the arrays so we don't have to create a new\n // array every frame.\n var temp = processing;\n processing = aAnimQueue;\n aAnimQueue = temp;\n while ( processing.length ) {\n processing.shift()[ 1 ]( time );\n }\n } else {\n // don't continue the interval, if unnecessary\n clearInterval( iIntervalId );\n iIntervalId = undefined;\n }\n }, 1000 / 50); // estimating support for 50 frames per second\n }\n\n return iRequestId;\n };\n\n // create a mock cancelAnimationFrame function\n $.cancelAnimationFrame = function( requestId ) {\n // find the request ID and remove it\n var i, j;\n for ( i = 0, j = aAnimQueue.length; i < j; i += 1 ) {\n if ( aAnimQueue[ i ][ 0 ] === requestId ) {\n aAnimQueue.splice( i, 1 );\n return;\n }\n }\n\n // If it's not in the queue, it may be in the set we're currently\n // processing (if cancelAnimationFrame is called from within a\n // requestAnimationFrame callback).\n for ( i = 0, j = processing.length; i < j; i += 1 ) {\n if ( processing[ i ][ 0 ] === requestId ) {\n processing.splice( i, 1 );\n return;\n }\n }\n };\n }\n })( window );\n\n /**\n * @private\n * @inner\n * @function\n * @param {Element} element\n * @param {Boolean} [isFixed]\n * @returns {Element}\n */\n function getOffsetParent( element, isFixed ) {\n if ( isFixed && element != document.body ) {\n return document.body;\n } else {\n return element.offsetParent;\n }\n }\n\n}(OpenSeadragon));\n\n\n// Universal Module Definition, supports CommonJS, AMD and simple script tag\n(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // expose as amd module\n define([], factory);\n } else if (typeof module === 'object' && module.exports) {\n // expose as commonjs module\n module.exports = factory();\n } else {\n // expose as window.OpenSeadragon\n root.OpenSeadragon = factory();\n }\n}(this, function () {\n return OpenSeadragon;\n}));\n","/*\n * OpenSeadragon - full-screen support functions\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ) {\n /**\n * Determine native full screen support we can get from the browser.\n * @member fullScreenApi\n * @memberof OpenSeadragon\n * @type {object}\n * @property {Boolean} supportsFullScreen Return true if full screen API is supported.\n * @property {Function} isFullScreen Return true if currently in full screen mode.\n * @property {Function} getFullScreenElement Return the element currently in full screen mode.\n * @property {Function} requestFullScreen Make a request to go in full screen mode.\n * @property {Function} exitFullScreen Make a request to exit full screen mode.\n * @property {Function} cancelFullScreen Deprecated, use exitFullScreen instead.\n * @property {String} fullScreenEventName Event fired when the full screen mode change.\n * @property {String} fullScreenErrorEventName Event fired when a request to go\n * in full screen mode failed.\n */\n var fullScreenApi = {\n supportsFullScreen: false,\n isFullScreen: function() { return false; },\n getFullScreenElement: function() { return null; },\n requestFullScreen: function() {},\n exitFullScreen: function() {},\n cancelFullScreen: function() {},\n fullScreenEventName: '',\n fullScreenErrorEventName: ''\n };\n\n // check for native support\n if ( document.exitFullscreen ) {\n // W3C standard\n fullScreenApi.supportsFullScreen = true;\n fullScreenApi.getFullScreenElement = function() {\n return document.fullscreenElement;\n };\n fullScreenApi.requestFullScreen = function( element ) {\n return element.requestFullscreen();\n };\n fullScreenApi.exitFullScreen = function() {\n document.exitFullscreen();\n };\n fullScreenApi.fullScreenEventName = \"fullscreenchange\";\n fullScreenApi.fullScreenErrorEventName = \"fullscreenerror\";\n } else if ( document.msExitFullscreen ) {\n // IE 11\n fullScreenApi.supportsFullScreen = true;\n fullScreenApi.getFullScreenElement = function() {\n return document.msFullscreenElement;\n };\n fullScreenApi.requestFullScreen = function( element ) {\n return element.msRequestFullscreen();\n };\n fullScreenApi.exitFullScreen = function() {\n document.msExitFullscreen();\n };\n fullScreenApi.fullScreenEventName = \"MSFullscreenChange\";\n fullScreenApi.fullScreenErrorEventName = \"MSFullscreenError\";\n } else if ( document.webkitExitFullscreen ) {\n // Recent webkit\n fullScreenApi.supportsFullScreen = true;\n fullScreenApi.getFullScreenElement = function() {\n return document.webkitFullscreenElement;\n };\n fullScreenApi.requestFullScreen = function( element ) {\n return element.webkitRequestFullscreen();\n };\n fullScreenApi.exitFullScreen = function() {\n document.webkitExitFullscreen();\n };\n fullScreenApi.fullScreenEventName = \"webkitfullscreenchange\";\n fullScreenApi.fullScreenErrorEventName = \"webkitfullscreenerror\";\n } else if ( document.webkitCancelFullScreen ) {\n // Old webkit\n fullScreenApi.supportsFullScreen = true;\n fullScreenApi.getFullScreenElement = function() {\n return document.webkitCurrentFullScreenElement;\n };\n fullScreenApi.requestFullScreen = function( element ) {\n return element.webkitRequestFullScreen();\n };\n fullScreenApi.exitFullScreen = function() {\n document.webkitCancelFullScreen();\n };\n fullScreenApi.fullScreenEventName = \"webkitfullscreenchange\";\n fullScreenApi.fullScreenErrorEventName = \"webkitfullscreenerror\";\n } else if ( document.mozCancelFullScreen ) {\n // Firefox\n fullScreenApi.supportsFullScreen = true;\n fullScreenApi.getFullScreenElement = function() {\n return document.mozFullScreenElement;\n };\n fullScreenApi.requestFullScreen = function( element ) {\n return element.mozRequestFullScreen();\n };\n fullScreenApi.exitFullScreen = function() {\n document.mozCancelFullScreen();\n };\n fullScreenApi.fullScreenEventName = \"mozfullscreenchange\";\n fullScreenApi.fullScreenErrorEventName = \"mozfullscreenerror\";\n }\n fullScreenApi.isFullScreen = function() {\n return fullScreenApi.getFullScreenElement() !== null;\n };\n fullScreenApi.cancelFullScreen = function() {\n $.console.error(\"cancelFullScreen is deprecated. Use exitFullScreen instead.\");\n fullScreenApi.exitFullScreen();\n };\n\n // export api\n $.extend( $, fullScreenApi );\n\n})( OpenSeadragon );\n","/*\n * OpenSeadragon - EventSource\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function($){\n\n/**\n * Event handler method signature used by all OpenSeadragon events.\n *\n * @callback EventHandler\n * @memberof OpenSeadragon\n * @param {Object} event - See individual events for event-specific properties.\n */\n\n\n/**\n * @class EventSource\n * @classdesc For use by classes which want to support custom, non-browser events.\n *\n * @memberof OpenSeadragon\n */\n$.EventSource = function() {\n this.events = {};\n};\n\n/** @lends OpenSeadragon.EventSource.prototype */\n$.EventSource.prototype = {\n\n /**\n * Add an event handler to be triggered only once (or a given number of times)\n * for a given event.\n * @function\n * @param {String} eventName - Name of event to register.\n * @param {OpenSeadragon.EventHandler} handler - Function to call when event\n * is triggered.\n * @param {Object} [userData=null] - Arbitrary object to be passed unchanged\n * to the handler.\n * @param {Number} [times=1] - The number of times to handle the event\n * before removing it.\n */\n addOnceHandler: function(eventName, handler, userData, times) {\n var self = this;\n times = times || 1;\n var count = 0;\n var onceHandler = function(event) {\n count++;\n if (count === times) {\n self.removeHandler(eventName, onceHandler);\n }\n handler(event);\n };\n this.addHandler(eventName, onceHandler, userData);\n },\n\n /**\n * Add an event handler for a given event.\n * @function\n * @param {String} eventName - Name of event to register.\n * @param {OpenSeadragon.EventHandler} handler - Function to call when event is triggered.\n * @param {Object} [userData=null] - Arbitrary object to be passed unchanged to the handler.\n */\n addHandler: function ( eventName, handler, userData ) {\n var events = this.events[ eventName ];\n if ( !events ) {\n this.events[ eventName ] = events = [];\n }\n if ( handler && $.isFunction( handler ) ) {\n events[ events.length ] = { handler: handler, userData: userData || null };\n }\n },\n\n /**\n * Remove a specific event handler for a given event.\n * @function\n * @param {String} eventName - Name of event for which the handler is to be removed.\n * @param {OpenSeadragon.EventHandler} handler - Function to be removed.\n */\n removeHandler: function ( eventName, handler ) {\n var events = this.events[ eventName ],\n handlers = [],\n i;\n if ( !events ) {\n return;\n }\n if ( $.isArray( events ) ) {\n for ( i = 0; i < events.length; i++ ) {\n if ( events[i].handler !== handler ) {\n handlers.push( events[ i ] );\n }\n }\n this.events[ eventName ] = handlers;\n }\n },\n\n\n /**\n * Remove all event handlers for a given event type. If no type is given all\n * event handlers for every event type are removed.\n * @function\n * @param {String} eventName - Name of event for which all handlers are to be removed.\n */\n removeAllHandlers: function( eventName ) {\n if ( eventName ){\n this.events[ eventName ] = [];\n } else{\n for ( var eventType in this.events ) {\n this.events[ eventType ] = [];\n }\n }\n },\n\n /**\n * Get a function which iterates the list of all handlers registered for a given event, calling the handler for each.\n * @function\n * @param {String} eventName - Name of event to get handlers for.\n */\n getHandler: function ( eventName ) {\n var events = this.events[ eventName ];\n if ( !events || !events.length ) {\n return null;\n }\n events = events.length === 1 ?\n [ events[ 0 ] ] :\n Array.apply( null, events );\n return function ( source, args ) {\n var i,\n length = events.length;\n for ( i = 0; i < length; i++ ) {\n if ( events[ i ] ) {\n args.eventSource = source;\n args.userData = events[ i ].userData;\n events[ i ].handler( args );\n }\n }\n };\n },\n\n /**\n * Trigger an event, optionally passing additional information.\n * @function\n * @param {String} eventName - Name of event to register.\n * @param {Object} eventArgs - Event-specific data.\n */\n raiseEvent: function( eventName, eventArgs ) {\n //uncomment if you want to get a log of all events\n //$.console.log( eventName );\n var handler = this.getHandler( eventName );\n\n if ( handler ) {\n if ( !eventArgs ) {\n eventArgs = {};\n }\n\n handler( this, eventArgs );\n }\n }\n};\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - MouseTracker\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function ( $ ) {\n\n // All MouseTracker instances\n var MOUSETRACKERS = [];\n\n // dictionary from hash to private properties\n var THIS = {};\n\n\n /**\n * @class MouseTracker\n * @classdesc Provides simplified handling of common pointer device (mouse, touch, pen, etc.) gestures\n * and keyboard events on a specified element.\n * @memberof OpenSeadragon\n * @param {Object} options\n * Allows configurable properties to be entirely specified by passing\n * an options object to the constructor. The constructor also supports\n * the original positional arguments 'element', 'clickTimeThreshold',\n * and 'clickDistThreshold' in that order.\n * @param {Element|String} options.element\n * A reference to an element or an element id for which the pointer/key\n * events will be monitored.\n * @param {Boolean} [options.startDisabled=false]\n * If true, event tracking on the element will not start until\n * {@link OpenSeadragon.MouseTracker.setTracking|setTracking} is called.\n * @param {Number} options.clickTimeThreshold\n * The number of milliseconds within which a pointer down-up event combination\n * will be treated as a click gesture.\n * @param {Number} options.clickDistThreshold\n * The maximum distance allowed between a pointer down event and a pointer up event\n * to be treated as a click gesture.\n * @param {Number} options.dblClickTimeThreshold\n * The number of milliseconds within which two pointer down-up event combinations\n * will be treated as a double-click gesture.\n * @param {Number} options.dblClickDistThreshold\n * The maximum distance allowed between two pointer click events\n * to be treated as a click gesture.\n * @param {Number} [options.stopDelay=50]\n * The number of milliseconds without pointer move before the stop\n * event is fired.\n * @param {OpenSeadragon.EventHandler} [options.enterHandler=null]\n * An optional handler for pointer enter.\n * @param {OpenSeadragon.EventHandler} [options.exitHandler=null]\n * An optional handler for pointer exit.\n * @param {OpenSeadragon.EventHandler} [options.pressHandler=null]\n * An optional handler for pointer press.\n * @param {OpenSeadragon.EventHandler} [options.nonPrimaryPressHandler=null]\n * An optional handler for pointer non-primary button press.\n * @param {OpenSeadragon.EventHandler} [options.releaseHandler=null]\n * An optional handler for pointer release.\n * @param {OpenSeadragon.EventHandler} [options.nonPrimaryReleaseHandler=null]\n * An optional handler for pointer non-primary button release.\n * @param {OpenSeadragon.EventHandler} [options.moveHandler=null]\n * An optional handler for pointer move.\n * @param {OpenSeadragon.EventHandler} [options.scrollHandler=null]\n * An optional handler for mouse wheel scroll.\n * @param {OpenSeadragon.EventHandler} [options.clickHandler=null]\n * An optional handler for pointer click.\n * @param {OpenSeadragon.EventHandler} [options.dblClickHandler=null]\n * An optional handler for pointer double-click.\n * @param {OpenSeadragon.EventHandler} [options.dragHandler=null]\n * An optional handler for the drag gesture.\n * @param {OpenSeadragon.EventHandler} [options.dragEndHandler=null]\n * An optional handler for after a drag gesture.\n * @param {OpenSeadragon.EventHandler} [options.pinchHandler=null]\n * An optional handler for the pinch gesture.\n * @param {OpenSeadragon.EventHandler} [options.keyDownHandler=null]\n * An optional handler for keydown.\n * @param {OpenSeadragon.EventHandler} [options.keyUpHandler=null]\n * An optional handler for keyup.\n * @param {OpenSeadragon.EventHandler} [options.keyHandler=null]\n * An optional handler for keypress.\n * @param {OpenSeadragon.EventHandler} [options.focusHandler=null]\n * An optional handler for focus.\n * @param {OpenSeadragon.EventHandler} [options.blurHandler=null]\n * An optional handler for blur.\n * @param {Object} [options.userData=null]\n * Arbitrary object to be passed unchanged to any attached handler methods.\n */\n $.MouseTracker = function ( options ) {\n\n MOUSETRACKERS.push( this );\n\n var args = arguments;\n\n if ( !$.isPlainObject( options ) ) {\n options = {\n element: args[ 0 ],\n clickTimeThreshold: args[ 1 ],\n clickDistThreshold: args[ 2 ]\n };\n }\n\n this.hash = Math.random(); // An unique hash for this tracker.\n /**\n * The element for which pointer events are being monitored.\n * @member {Element} element\n * @memberof OpenSeadragon.MouseTracker#\n */\n this.element = $.getElement( options.element );\n /**\n * The number of milliseconds within which a pointer down-up event combination\n * will be treated as a click gesture.\n * @member {Number} clickTimeThreshold\n * @memberof OpenSeadragon.MouseTracker#\n */\n this.clickTimeThreshold = options.clickTimeThreshold || $.DEFAULT_SETTINGS.clickTimeThreshold;\n /**\n * The maximum distance allowed between a pointer down event and a pointer up event\n * to be treated as a click gesture.\n * @member {Number} clickDistThreshold\n * @memberof OpenSeadragon.MouseTracker#\n */\n this.clickDistThreshold = options.clickDistThreshold || $.DEFAULT_SETTINGS.clickDistThreshold;\n /**\n * The number of milliseconds within which two pointer down-up event combinations\n * will be treated as a double-click gesture.\n * @member {Number} dblClickTimeThreshold\n * @memberof OpenSeadragon.MouseTracker#\n */\n this.dblClickTimeThreshold = options.dblClickTimeThreshold || $.DEFAULT_SETTINGS.dblClickTimeThreshold;\n /**\n * The maximum distance allowed between two pointer click events\n * to be treated as a click gesture.\n * @member {Number} clickDistThreshold\n * @memberof OpenSeadragon.MouseTracker#\n */\n this.dblClickDistThreshold = options.dblClickDistThreshold || $.DEFAULT_SETTINGS.dblClickDistThreshold;\n /*eslint-disable no-multi-spaces*/\n this.userData = options.userData || null;\n this.stopDelay = options.stopDelay || 50;\n\n this.enterHandler = options.enterHandler || null;\n this.exitHandler = options.exitHandler || null;\n this.pressHandler = options.pressHandler || null;\n this.nonPrimaryPressHandler = options.nonPrimaryPressHandler || null;\n this.releaseHandler = options.releaseHandler || null;\n this.nonPrimaryReleaseHandler = options.nonPrimaryReleaseHandler || null;\n this.moveHandler = options.moveHandler || null;\n this.scrollHandler = options.scrollHandler || null;\n this.clickHandler = options.clickHandler || null;\n this.dblClickHandler = options.dblClickHandler || null;\n this.dragHandler = options.dragHandler || null;\n this.dragEndHandler = options.dragEndHandler || null;\n this.pinchHandler = options.pinchHandler || null;\n this.stopHandler = options.stopHandler || null;\n this.keyDownHandler = options.keyDownHandler || null;\n this.keyUpHandler = options.keyUpHandler || null;\n this.keyHandler = options.keyHandler || null;\n this.focusHandler = options.focusHandler || null;\n this.blurHandler = options.blurHandler || null;\n /*eslint-enable no-multi-spaces*/\n\n //Store private properties in a scope sealed hash map\n var _this = this;\n\n /**\n * @private\n * @property {Boolean} tracking\n * Are we currently tracking pointer events for this element.\n */\n THIS[ this.hash ] = {\n click: function ( event ) { onClick( _this, event ); },\n dblclick: function ( event ) { onDblClick( _this, event ); },\n keydown: function ( event ) { onKeyDown( _this, event ); },\n keyup: function ( event ) { onKeyUp( _this, event ); },\n keypress: function ( event ) { onKeyPress( _this, event ); },\n focus: function ( event ) { onFocus( _this, event ); },\n blur: function ( event ) { onBlur( _this, event ); },\n\n wheel: function ( event ) { onWheel( _this, event ); },\n mousewheel: function ( event ) { onMouseWheel( _this, event ); },\n DOMMouseScroll: function ( event ) { onMouseWheel( _this, event ); },\n MozMousePixelScroll: function ( event ) { onMouseWheel( _this, event ); },\n\n mouseenter: function ( event ) { onMouseEnter( _this, event ); }, // Used on IE8 only\n mouseleave: function ( event ) { onMouseLeave( _this, event ); }, // Used on IE8 only\n mouseover: function ( event ) { onMouseOver( _this, event ); },\n mouseout: function ( event ) { onMouseOut( _this, event ); },\n mousedown: function ( event ) { onMouseDown( _this, event ); },\n mouseup: function ( event ) { onMouseUp( _this, event ); },\n mouseupcaptured: function ( event ) { onMouseUpCaptured( _this, event ); },\n mousemove: function ( event ) { onMouseMove( _this, event ); },\n mousemovecaptured: function ( event ) { onMouseMoveCaptured( _this, event ); },\n\n touchstart: function ( event ) { onTouchStart( _this, event ); },\n touchend: function ( event ) { onTouchEnd( _this, event ); },\n touchendcaptured: function ( event ) { onTouchEndCaptured( _this, event ); },\n touchmove: function ( event ) { onTouchMove( _this, event ); },\n touchmovecaptured: function ( event ) { onTouchMoveCaptured( _this, event ); },\n touchcancel: function ( event ) { onTouchCancel( _this, event ); },\n\n gesturestart: function ( event ) { onGestureStart( _this, event ); },\n gesturechange: function ( event ) { onGestureChange( _this, event ); },\n\n pointerover: function ( event ) { onPointerOver( _this, event ); },\n MSPointerOver: function ( event ) { onPointerOver( _this, event ); },\n pointerout: function ( event ) { onPointerOut( _this, event ); },\n MSPointerOut: function ( event ) { onPointerOut( _this, event ); },\n pointerdown: function ( event ) { onPointerDown( _this, event ); },\n MSPointerDown: function ( event ) { onPointerDown( _this, event ); },\n pointerup: function ( event ) { onPointerUp( _this, event ); },\n MSPointerUp: function ( event ) { onPointerUp( _this, event ); },\n pointermove: function ( event ) { onPointerMove( _this, event ); },\n MSPointerMove: function ( event ) { onPointerMove( _this, event ); },\n pointercancel: function ( event ) { onPointerCancel( _this, event ); },\n MSPointerCancel: function ( event ) { onPointerCancel( _this, event ); },\n pointerupcaptured: function ( event ) { onPointerUpCaptured( _this, event ); },\n pointermovecaptured: function ( event ) { onPointerMoveCaptured( _this, event ); },\n\n tracking: false,\n\n // Active pointers lists. Array of GesturePointList objects, one for each pointer device type.\n // GesturePointList objects are added each time a pointer is tracked by a new pointer device type (see getActivePointersListByType()).\n // Active pointers are any pointer being tracked for this element which are in the hit-test area\n // of the element (for hover-capable devices) and/or have contact or a button press initiated in the element.\n activePointersLists: [],\n\n // Tracking for double-click gesture\n lastClickPos: null,\n dblClickTimeOut: null,\n\n // Tracking for pinch gesture\n pinchGPoints: [],\n lastPinchDist: 0,\n currentPinchDist: 0,\n lastPinchCenter: null,\n currentPinchCenter: null\n };\n\n if ( !options.startDisabled ) {\n this.setTracking( true );\n }\n };\n\n /** @lends OpenSeadragon.MouseTracker.prototype */\n $.MouseTracker.prototype = {\n\n /**\n * Clean up any events or objects created by the tracker.\n * @function\n */\n destroy: function () {\n var i;\n\n stopTracking( this );\n this.element = null;\n\n for ( i = 0; i < MOUSETRACKERS.length; i++ ) {\n if ( MOUSETRACKERS[ i ] === this ) {\n MOUSETRACKERS.splice( i, 1 );\n break;\n }\n }\n\n THIS[ this.hash ] = null;\n delete THIS[ this.hash ];\n },\n\n /**\n * Are we currently tracking events on this element.\n * @deprecated Just use this.tracking\n * @function\n * @returns {Boolean} Are we currently tracking events on this element.\n */\n isTracking: function () {\n return THIS[ this.hash ].tracking;\n },\n\n /**\n * Enable or disable whether or not we are tracking events on this element.\n * @function\n * @param {Boolean} track True to start tracking, false to stop tracking.\n * @returns {OpenSeadragon.MouseTracker} Chainable.\n */\n setTracking: function ( track ) {\n if ( track ) {\n startTracking( this );\n } else {\n stopTracking( this );\n }\n //chain\n return this;\n },\n\n /**\n * Returns the {@link OpenSeadragon.MouseTracker.GesturePointList|GesturePointList} for all but the given pointer device type.\n * @function\n * @param {String} type - The pointer device type: \"mouse\", \"touch\", \"pen\", etc.\n * @returns {Array.}\n */\n getActivePointersListsExceptType: function ( type ) {\n var delegate = THIS[ this.hash ];\n var listArray = [];\n\n for (var i = 0; i < delegate.activePointersLists.length; ++i) {\n if (delegate.activePointersLists[i].type !== type) {\n listArray.push(delegate.activePointersLists[i]);\n }\n }\n\n return listArray;\n },\n\n /**\n * Returns the {@link OpenSeadragon.MouseTracker.GesturePointList|GesturePointList} for the given pointer device type,\n * creating and caching a new {@link OpenSeadragon.MouseTracker.GesturePointList|GesturePointList} if one doesn't already exist for the type.\n * @function\n * @param {String} type - The pointer device type: \"mouse\", \"touch\", \"pen\", etc.\n * @returns {OpenSeadragon.MouseTracker.GesturePointList}\n */\n getActivePointersListByType: function ( type ) {\n var delegate = THIS[ this.hash ],\n i,\n len = delegate.activePointersLists.length,\n list;\n\n for ( i = 0; i < len; i++ ) {\n if ( delegate.activePointersLists[ i ].type === type ) {\n return delegate.activePointersLists[ i ];\n }\n }\n\n list = new $.MouseTracker.GesturePointList( type );\n delegate.activePointersLists.push( list );\n return list;\n },\n\n /**\n * Returns the total number of pointers currently active on the tracked element.\n * @function\n * @returns {Number}\n */\n getActivePointerCount: function () {\n var delegate = THIS[ this.hash ],\n i,\n len = delegate.activePointersLists.length,\n count = 0;\n\n for ( i = 0; i < len; i++ ) {\n count += delegate.activePointersLists[ i ].getLength();\n }\n\n return count;\n },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {Number} event.pointers\n * Number of pointers (all types) active in the tracked element.\n * @param {Boolean} event.insideElementPressed\n * True if the left mouse button is currently being pressed and was\n * initiated inside the tracked element, otherwise false.\n * @param {Boolean} event.buttonDownAny\n * Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n enterHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {Number} event.pointers\n * Number of pointers (all types) active in the tracked element.\n * @param {Boolean} event.insideElementPressed\n * True if the left mouse button is currently being pressed and was\n * initiated inside the tracked element, otherwise false.\n * @param {Boolean} event.buttonDownAny\n * Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n exitHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n pressHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.button\n * Button which caused the event.\n * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n nonPrimaryPressHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {Boolean} event.insideElementPressed\n * True if the left mouse button is currently being pressed and was\n * initiated inside the tracked element, otherwise false.\n * @param {Boolean} event.insideElementReleased\n * True if the cursor inside the tracked element when the button was released.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n releaseHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.button\n * Button which caused the event.\n * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n nonPrimaryReleaseHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n moveHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.scroll\n * The scroll delta for the event.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. Touch devices no longer generate scroll event.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n scrollHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Boolean} event.quick\n * True only if the clickDistThreshold and clickTimeThreshold are both passed. Useful for ignoring drag events.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n clickHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n dblClickHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {OpenSeadragon.Point} event.delta\n * The x,y components of the difference between the current position and the last drag event position. Useful for ignoring or weighting the events.\n * @param {Number} event.speed\n * Current computed speed, in pixels per second.\n * @param {Number} event.direction\n * Current computed direction, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n dragHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.speed\n * Speed at the end of a drag gesture, in pixels per second.\n * @param {Number} event.direction\n * Direction at the end of a drag gesture, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n dragEndHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {Array.} event.gesturePoints\n * Gesture points associated with the gesture. Velocity data can be found here.\n * @param {OpenSeadragon.Point} event.lastCenter\n * The previous center point of the two pinch contact points relative to the tracked element.\n * @param {OpenSeadragon.Point} event.center\n * The center point of the two pinch contact points relative to the tracked element.\n * @param {Number} event.lastDistance\n * The previous distance between the two pinch contact points in CSS pixels.\n * @param {Number} event.distance\n * The distance between the two pinch contact points in CSS pixels.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n pinchHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {String} event.pointerType\n * \"mouse\", \"touch\", \"pen\", etc.\n * @param {OpenSeadragon.Point} event.position\n * The position of the event relative to the tracked element.\n * @param {Number} event.buttons\n * Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @param {Boolean} event.isTouchEvent\n * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n stopHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {Number} event.keyCode\n * The key code that was pressed.\n * @param {Boolean} event.ctrl\n * True if the ctrl key was pressed during this event.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Boolean} event.alt\n * True if the alt key was pressed during this event.\n * @param {Boolean} event.meta\n * True if the meta key was pressed during this event.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n keyDownHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {Number} event.keyCode\n * The key code that was pressed.\n * @param {Boolean} event.ctrl\n * True if the ctrl key was pressed during this event.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Boolean} event.alt\n * True if the alt key was pressed during this event.\n * @param {Boolean} event.meta\n * True if the meta key was pressed during this event.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n keyUpHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {Number} event.keyCode\n * The key code that was pressed.\n * @param {Boolean} event.ctrl\n * True if the ctrl key was pressed during this event.\n * @param {Boolean} event.shift\n * True if the shift key was pressed during this event.\n * @param {Boolean} event.alt\n * True if the alt key was pressed during this event.\n * @param {Boolean} event.meta\n * True if the meta key was pressed during this event.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n keyHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n focusHandler: function () { },\n\n /**\n * Implement or assign implementation to these handlers during or after\n * calling the constructor.\n * @function\n * @param {Object} event\n * @param {OpenSeadragon.MouseTracker} event.eventSource\n * A reference to the tracker instance.\n * @param {Object} event.originalEvent\n * The original event object.\n * @param {Boolean} event.preventDefaultAction\n * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.\n * @param {Object} event.userData\n * Arbitrary user-defined object.\n */\n blurHandler: function () { }\n };\n\n /**\n * Resets all active mousetrakers. (Added to patch issue #697 \"Mouse up outside map will cause \"canvas-drag\" event to stick\")\n *\n * @private\n * @member resetAllMouseTrackers\n * @memberof OpenSeadragon.MouseTracker\n */\n $.MouseTracker.resetAllMouseTrackers = function(){\n for(var i = 0; i < MOUSETRACKERS.length; i++){\n if (MOUSETRACKERS[i].isTracking()){\n MOUSETRACKERS[i].setTracking(false);\n MOUSETRACKERS[i].setTracking(true);\n }\n }\n };\n\n /**\n * Provides continuous computation of velocity (speed and direction) of active pointers.\n * This is a singleton, used by all MouseTracker instances, as it is unlikely there will ever be more than\n * two active gesture pointers at a time.\n *\n * @private\n * @member gesturePointVelocityTracker\n * @memberof OpenSeadragon.MouseTracker\n */\n $.MouseTracker.gesturePointVelocityTracker = (function () {\n var trackerPoints = [],\n intervalId = 0,\n lastTime = 0;\n\n // Generates a unique identifier for a tracked gesture point\n var _generateGuid = function ( tracker, gPoint ) {\n return tracker.hash.toString() + gPoint.type + gPoint.id.toString();\n };\n\n // Interval timer callback. Computes velocity for all tracked gesture points.\n var _doTracking = function () {\n var i,\n len = trackerPoints.length,\n trackPoint,\n gPoint,\n now = $.now(),\n elapsedTime,\n distance,\n speed;\n\n elapsedTime = now - lastTime;\n lastTime = now;\n\n for ( i = 0; i < len; i++ ) {\n trackPoint = trackerPoints[ i ];\n gPoint = trackPoint.gPoint;\n // Math.atan2 gives us just what we need for a velocity vector, as we can simply\n // use cos()/sin() to extract the x/y velocity components.\n gPoint.direction = Math.atan2( gPoint.currentPos.y - trackPoint.lastPos.y, gPoint.currentPos.x - trackPoint.lastPos.x );\n // speed = distance / elapsed time\n distance = trackPoint.lastPos.distanceTo( gPoint.currentPos );\n trackPoint.lastPos = gPoint.currentPos;\n speed = 1000 * distance / ( elapsedTime + 1 );\n // Simple biased average, favors the most recent speed computation. Smooths out erratic gestures a bit.\n gPoint.speed = 0.75 * speed + 0.25 * gPoint.speed;\n }\n };\n\n // Public. Add a gesture point to be tracked\n var addPoint = function ( tracker, gPoint ) {\n var guid = _generateGuid( tracker, gPoint );\n\n trackerPoints.push(\n {\n guid: guid,\n gPoint: gPoint,\n lastPos: gPoint.currentPos\n } );\n\n // Only fire up the interval timer when there's gesture pointers to track\n if ( trackerPoints.length === 1 ) {\n lastTime = $.now();\n intervalId = window.setInterval( _doTracking, 50 );\n }\n };\n\n // Public. Stop tracking a gesture point\n var removePoint = function ( tracker, gPoint ) {\n var guid = _generateGuid( tracker, gPoint ),\n i,\n len = trackerPoints.length;\n for ( i = 0; i < len; i++ ) {\n if ( trackerPoints[ i ].guid === guid ) {\n trackerPoints.splice( i, 1 );\n // Only run the interval timer if theres gesture pointers to track\n len--;\n if ( len === 0 ) {\n window.clearInterval( intervalId );\n }\n break;\n }\n }\n };\n\n return {\n addPoint: addPoint,\n removePoint: removePoint\n };\n } )();\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Pointer event model and feature detection\n///////////////////////////////////////////////////////////////////////////////\n\n $.MouseTracker.captureElement = document;\n\n /**\n * Detect available mouse wheel event name.\n */\n $.MouseTracker.wheelEventName = ( $.Browser.vendor == $.BROWSERS.IE && $.Browser.version > 8 ) ||\n ( 'onwheel' in document.createElement( 'div' ) ) ? 'wheel' : // Modern browsers support 'wheel'\n document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least 'mousewheel'\n 'DOMMouseScroll'; // Assume old Firefox\n\n /**\n * Detect legacy mouse capture support.\n */\n $.MouseTracker.supportsMouseCapture = (function () {\n var divElement = document.createElement( 'div' );\n return $.isFunction( divElement.setCapture ) && $.isFunction( divElement.releaseCapture );\n }());\n\n /**\n * Detect browser pointer device event model(s) and build appropriate list of events to subscribe to.\n */\n $.MouseTracker.subscribeEvents = [ \"click\", \"dblclick\", \"keydown\", \"keyup\", \"keypress\", \"focus\", \"blur\", $.MouseTracker.wheelEventName ];\n\n if( $.MouseTracker.wheelEventName == \"DOMMouseScroll\" ) {\n // Older Firefox\n $.MouseTracker.subscribeEvents.push( \"MozMousePixelScroll\" );\n }\n\n // Note: window.navigator.pointerEnable is deprecated on IE 11 and not part of W3C spec.\n if ( window.PointerEvent && ( window.navigator.pointerEnabled || $.Browser.vendor !== $.BROWSERS.IE ) ) {\n // IE11 and other W3C Pointer Event implementations (see http://www.w3.org/TR/pointerevents)\n $.MouseTracker.havePointerEvents = true;\n $.MouseTracker.subscribeEvents.push( \"pointerover\", \"pointerout\", \"pointerdown\", \"pointerup\", \"pointermove\", \"pointercancel\" );\n $.MouseTracker.unprefixedPointerEvents = true;\n if( navigator.maxTouchPoints ) {\n $.MouseTracker.maxTouchPoints = navigator.maxTouchPoints;\n } else {\n $.MouseTracker.maxTouchPoints = 0;\n }\n $.MouseTracker.haveMouseEnter = false;\n } else if ( window.MSPointerEvent && window.navigator.msPointerEnabled ) {\n // IE10\n $.MouseTracker.havePointerEvents = true;\n $.MouseTracker.subscribeEvents.push( \"MSPointerOver\", \"MSPointerOut\", \"MSPointerDown\", \"MSPointerUp\", \"MSPointerMove\", \"MSPointerCancel\" );\n $.MouseTracker.unprefixedPointerEvents = false;\n if( navigator.msMaxTouchPoints ) {\n $.MouseTracker.maxTouchPoints = navigator.msMaxTouchPoints;\n } else {\n $.MouseTracker.maxTouchPoints = 0;\n }\n $.MouseTracker.haveMouseEnter = false;\n } else {\n // Legacy W3C mouse events\n $.MouseTracker.havePointerEvents = false;\n if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {\n $.MouseTracker.subscribeEvents.push( \"mouseenter\", \"mouseleave\" );\n $.MouseTracker.haveMouseEnter = true;\n } else {\n $.MouseTracker.subscribeEvents.push( \"mouseover\", \"mouseout\" );\n $.MouseTracker.haveMouseEnter = false;\n }\n $.MouseTracker.subscribeEvents.push( \"mousedown\", \"mouseup\", \"mousemove\" );\n if ( 'ontouchstart' in window ) {\n // iOS, Android, and other W3c Touch Event implementations\n // (see http://www.w3.org/TR/touch-events/)\n // (see https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html)\n // (see https://developer.apple.com/library/safari/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html)\n $.MouseTracker.subscribeEvents.push( \"touchstart\", \"touchend\", \"touchmove\", \"touchcancel\" );\n }\n if ( 'ongesturestart' in window ) {\n // iOS (see https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html)\n // Subscribe to these to prevent default gesture handling\n $.MouseTracker.subscribeEvents.push( \"gesturestart\", \"gesturechange\" );\n }\n $.MouseTracker.mousePointerId = \"legacy-mouse\";\n $.MouseTracker.maxTouchPoints = 10;\n }\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes and typedefs\n///////////////////////////////////////////////////////////////////////////////\n\n /**\n * Represents a point of contact on the screen made by a mouse cursor, pen, touch, or other pointer device.\n *\n * @typedef {Object} GesturePoint\n * @memberof OpenSeadragon.MouseTracker\n *\n * @property {Number} id\n * Identifier unique from all other active GesturePoints for a given pointer device.\n * @property {String} type\n * The pointer device type: \"mouse\", \"touch\", \"pen\", etc.\n * @property {Boolean} captured\n * True if events for the gesture point are captured to the tracked element.\n * @property {Boolean} isPrimary\n * True if the gesture point is a master pointer amongst the set of active pointers for each pointer type. True for mouse and primary (first) touch/pen pointers.\n * @property {Boolean} insideElementPressed\n * True if button pressed or contact point initiated inside the screen area of the tracked element.\n * @property {Boolean} insideElement\n * True if pointer or contact point is currently inside the bounds of the tracked element.\n * @property {Number} speed\n * Current computed speed, in pixels per second.\n * @property {Number} direction\n * Current computed direction, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0.\n * @property {OpenSeadragon.Point} contactPos\n * The initial pointer contact position, relative to the page including any scrolling. Only valid if the pointer has contact (pressed, touch contact, pen contact).\n * @property {Number} contactTime\n * The initial pointer contact time, in milliseconds. Only valid if the pointer has contact (pressed, touch contact, pen contact).\n * @property {OpenSeadragon.Point} lastPos\n * The last pointer position, relative to the page including any scrolling.\n * @property {Number} lastTime\n * The last pointer contact time, in milliseconds.\n * @property {OpenSeadragon.Point} currentPos\n * The current pointer position, relative to the page including any scrolling.\n * @property {Number} currentTime\n * The current pointer contact time, in milliseconds.\n */\n\n\n /**\n * @class GesturePointList\n * @classdesc Provides an abstraction for a set of active {@link OpenSeadragon.MouseTracker.GesturePoint|GesturePoint} objects for a given pointer device type.\n * Active pointers are any pointer being tracked for this element which are in the hit-test area\n * of the element (for hover-capable devices) and/or have contact or a button press initiated in the element.\n * @memberof OpenSeadragon.MouseTracker\n * @param {String} type - The pointer device type: \"mouse\", \"touch\", \"pen\", etc.\n */\n $.MouseTracker.GesturePointList = function ( type ) {\n this._gPoints = [];\n /**\n * The pointer device type: \"mouse\", \"touch\", \"pen\", etc.\n * @member {String} type\n * @memberof OpenSeadragon.MouseTracker.GesturePointList#\n */\n this.type = type;\n /**\n * Current buttons pressed for the device.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @member {Number} buttons\n * @memberof OpenSeadragon.MouseTracker.GesturePointList#\n */\n this.buttons = 0;\n /**\n * Current number of contact points (touch points, mouse down, etc.) for the device.\n * @member {Number} contacts\n * @memberof OpenSeadragon.MouseTracker.GesturePointList#\n */\n this.contacts = 0;\n /**\n * Current number of clicks for the device. Used for multiple click gesture tracking.\n * @member {Number} clicks\n * @memberof OpenSeadragon.MouseTracker.GesturePointList#\n */\n this.clicks = 0;\n /**\n * Current number of captured pointers for the device.\n * @member {Number} captureCount\n * @memberof OpenSeadragon.MouseTracker.GesturePointList#\n */\n this.captureCount = 0;\n };\n\n /** @lends OpenSeadragon.MouseTracker.GesturePointList.prototype */\n $.MouseTracker.GesturePointList.prototype = {\n /**\n * @function\n * @returns {Number} Number of gesture points in the list.\n */\n getLength: function () {\n return this._gPoints.length;\n },\n /**\n * @function\n * @returns {Array.} The list of gesture points in the list as an array (read-only).\n */\n asArray: function () {\n return this._gPoints;\n },\n /**\n * @function\n * @param {OpenSeadragon.MouseTracker.GesturePoint} gesturePoint - A gesture point to add to the list.\n * @returns {Number} Number of gesture points in the list.\n */\n add: function ( gp ) {\n return this._gPoints.push( gp );\n },\n /**\n * @function\n * @param {Number} id - The id of the gesture point to remove from the list.\n * @returns {Number} Number of gesture points in the list.\n */\n removeById: function ( id ) {\n var i,\n len = this._gPoints.length;\n for ( i = 0; i < len; i++ ) {\n if ( this._gPoints[ i ].id === id ) {\n this._gPoints.splice( i, 1 );\n break;\n }\n }\n return this._gPoints.length;\n },\n /**\n * @function\n * @param {Number} index - The index of the gesture point to retrieve from the list.\n * @returns {OpenSeadragon.MouseTracker.GesturePoint|null} The gesture point at the given index, or null if not found.\n */\n getByIndex: function ( index ) {\n if ( index < this._gPoints.length) {\n return this._gPoints[ index ];\n }\n\n return null;\n },\n /**\n * @function\n * @param {Number} id - The id of the gesture point to retrieve from the list.\n * @returns {OpenSeadragon.MouseTracker.GesturePoint|null} The gesture point with the given id, or null if not found.\n */\n getById: function ( id ) {\n var i,\n len = this._gPoints.length;\n for ( i = 0; i < len; i++ ) {\n if ( this._gPoints[ i ].id === id ) {\n return this._gPoints[ i ];\n }\n }\n return null;\n },\n /**\n * @function\n * @returns {OpenSeadragon.MouseTracker.GesturePoint|null} The primary gesture point in the list, or null if not found.\n */\n getPrimary: function ( id ) {\n var i,\n len = this._gPoints.length;\n for ( i = 0; i < len; i++ ) {\n if ( this._gPoints[ i ].isPrimary ) {\n return this._gPoints[ i ];\n }\n }\n return null;\n },\n\n /**\n * Increment this pointer's contact count.\n * It will evaluate whether this pointer type is allowed to have multiple contacts.\n * @function\n */\n addContact: function() {\n ++this.contacts;\n\n if (this.contacts > 1 && (this.type === \"mouse\" || this.type === \"pen\")) {\n this.contacts = 1;\n }\n },\n\n /**\n * Decrement this pointer's contact count.\n * It will make sure the count does not go below 0.\n * @function\n */\n removeContact: function() {\n --this.contacts;\n\n if (this.contacts < 0) {\n this.contacts = 0;\n }\n }\n };\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Utility functions\n///////////////////////////////////////////////////////////////////////////////\n\n /**\n * Removes all tracked pointers.\n * @private\n * @inner\n */\n function clearTrackedPointers( tracker ) {\n var delegate = THIS[ tracker.hash ],\n i,\n pointerListCount = delegate.activePointersLists.length;\n\n for ( i = 0; i < pointerListCount; i++ ) {\n if ( delegate.activePointersLists[ i ].captureCount > 0 ) {\n $.removeEvent(\n $.MouseTracker.captureElement,\n 'mousemove',\n delegate.mousemovecaptured,\n true\n );\n $.removeEvent(\n $.MouseTracker.captureElement,\n 'mouseup',\n delegate.mouseupcaptured,\n true\n );\n $.removeEvent(\n $.MouseTracker.captureElement,\n $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove',\n delegate.pointermovecaptured,\n true\n );\n $.removeEvent(\n $.MouseTracker.captureElement,\n $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp',\n delegate.pointerupcaptured,\n true\n );\n $.removeEvent(\n $.MouseTracker.captureElement,\n 'touchmove',\n delegate.touchmovecaptured,\n true\n );\n $.removeEvent(\n $.MouseTracker.captureElement,\n 'touchend',\n delegate.touchendcaptured,\n true\n );\n\n delegate.activePointersLists[ i ].captureCount = 0;\n }\n }\n\n for ( i = 0; i < pointerListCount; i++ ) {\n delegate.activePointersLists.pop();\n }\n }\n\n /**\n * Starts tracking pointer events on the tracked element.\n * @private\n * @inner\n */\n function startTracking( tracker ) {\n var delegate = THIS[ tracker.hash ],\n event,\n i;\n\n if ( !delegate.tracking ) {\n for ( i = 0; i < $.MouseTracker.subscribeEvents.length; i++ ) {\n event = $.MouseTracker.subscribeEvents[ i ];\n $.addEvent(\n tracker.element,\n event,\n delegate[ event ],\n false\n );\n }\n\n clearTrackedPointers( tracker );\n\n delegate.tracking = true;\n }\n }\n\n /**\n * Stops tracking pointer events on the tracked element.\n * @private\n * @inner\n */\n function stopTracking( tracker ) {\n var delegate = THIS[ tracker.hash ],\n event,\n i;\n\n if ( delegate.tracking ) {\n for ( i = 0; i < $.MouseTracker.subscribeEvents.length; i++ ) {\n event = $.MouseTracker.subscribeEvents[ i ];\n $.removeEvent(\n tracker.element,\n event,\n delegate[ event ],\n false\n );\n }\n\n clearTrackedPointers( tracker );\n\n delegate.tracking = false;\n }\n }\n\n /**\n * @private\n * @inner\n */\n function getCaptureEventParams( tracker, pointerType ) {\n var delegate = THIS[ tracker.hash ];\n\n if ( pointerType === 'pointerevent' ) {\n return {\n upName: $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp',\n upHandler: delegate.pointerupcaptured,\n moveName: $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove',\n moveHandler: delegate.pointermovecaptured\n };\n } else if ( pointerType === 'mouse' ) {\n return {\n upName: 'mouseup',\n upHandler: delegate.mouseupcaptured,\n moveName: 'mousemove',\n moveHandler: delegate.mousemovecaptured\n };\n } else if ( pointerType === 'touch' ) {\n return {\n upName: 'touchend',\n upHandler: delegate.touchendcaptured,\n moveName: 'touchmove',\n moveHandler: delegate.touchmovecaptured\n };\n } else {\n throw new Error( \"MouseTracker.getCaptureEventParams: Unknown pointer type.\" );\n }\n }\n\n /**\n * Begin capturing pointer events to the tracked element.\n * @private\n * @inner\n */\n function capturePointer( tracker, pointerType, pointerCount ) {\n var pointsList = tracker.getActivePointersListByType( pointerType ),\n eventParams;\n\n pointsList.captureCount += (pointerCount || 1);\n\n if ( pointsList.captureCount === 1 ) {\n if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {\n tracker.element.setCapture( true );\n } else {\n eventParams = getCaptureEventParams( tracker, $.MouseTracker.havePointerEvents ? 'pointerevent' : pointerType );\n // We emulate mouse capture by hanging listeners on the document object.\n // (Note we listen on the capture phase so the captured handlers will get called first)\n // eslint-disable-next-line no-use-before-define\n if (isInIframe && canAccessEvents(window.top)) {\n $.addEvent(\n window.top,\n eventParams.upName,\n eventParams.upHandler,\n true\n );\n }\n $.addEvent(\n $.MouseTracker.captureElement,\n eventParams.upName,\n eventParams.upHandler,\n true\n );\n $.addEvent(\n $.MouseTracker.captureElement,\n eventParams.moveName,\n eventParams.moveHandler,\n true\n );\n }\n }\n }\n\n\n /**\n * Stop capturing pointer events to the tracked element.\n * @private\n * @inner\n */\n function releasePointer( tracker, pointerType, pointerCount ) {\n var pointsList = tracker.getActivePointersListByType( pointerType ),\n eventParams;\n\n pointsList.captureCount -= (pointerCount || 1);\n\n if ( pointsList.captureCount === 0 ) {\n if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {\n tracker.element.releaseCapture();\n } else {\n eventParams = getCaptureEventParams( tracker, $.MouseTracker.havePointerEvents ? 'pointerevent' : pointerType );\n // We emulate mouse capture by hanging listeners on the document object.\n // (Note we listen on the capture phase so the captured handlers will get called first)\n // eslint-disable-next-line no-use-before-define\n if (isInIframe && canAccessEvents(window.top)) {\n $.removeEvent(\n window.top,\n eventParams.upName,\n eventParams.upHandler,\n true\n );\n }\n $.removeEvent(\n $.MouseTracker.captureElement,\n eventParams.moveName,\n eventParams.moveHandler,\n true\n );\n $.removeEvent(\n $.MouseTracker.captureElement,\n eventParams.upName,\n eventParams.upHandler,\n true\n );\n }\n }\n }\n\n\n /**\n * Gets a W3C Pointer Events model compatible pointer type string from a DOM pointer event.\n * IE10 used a long integer value, but the W3C specification (and IE11+) use a string \"mouse\", \"touch\", \"pen\", etc.\n * @private\n * @inner\n */\n function getPointerType( event ) {\n var pointerTypeStr;\n if ( $.MouseTracker.unprefixedPointerEvents ) {\n pointerTypeStr = event.pointerType;\n } else {\n // IE10\n // MSPOINTER_TYPE_TOUCH: 0x00000002\n // MSPOINTER_TYPE_PEN: 0x00000003\n // MSPOINTER_TYPE_MOUSE: 0x00000004\n switch( event.pointerType )\n {\n case 0x00000002:\n pointerTypeStr = 'touch';\n break;\n case 0x00000003:\n pointerTypeStr = 'pen';\n break;\n case 0x00000004:\n pointerTypeStr = 'mouse';\n break;\n default:\n pointerTypeStr = '';\n }\n }\n return pointerTypeStr;\n }\n\n\n /**\n * @private\n * @inner\n */\n function getMouseAbsolute( event ) {\n return $.getMousePosition( event );\n }\n\n /**\n * @private\n * @inner\n */\n function getMouseRelative( event, element ) {\n return getPointRelativeToAbsolute( getMouseAbsolute( event ), element );\n }\n\n /**\n * @private\n * @inner\n */\n function getPointRelativeToAbsolute( point, element ) {\n var offset = $.getElementOffset( element );\n return point.minus( offset );\n }\n\n /**\n * @private\n * @inner\n */\n function getCenterPoint( point1, point2 ) {\n return new $.Point( ( point1.x + point2.x ) / 2, ( point1.y + point2.y ) / 2 );\n }\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Device-specific DOM event handlers\n///////////////////////////////////////////////////////////////////////////////\n\n /**\n * @private\n * @inner\n */\n function onClick( tracker, event ) {\n if ( tracker.clickHandler ) {\n $.cancelEvent( event );\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onDblClick( tracker, event ) {\n if ( tracker.dblClickHandler ) {\n $.cancelEvent( event );\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onKeyDown( tracker, event ) {\n //$.console.log( \"keydown %s %s %s %s %s\", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey );\n var propagate;\n if ( tracker.keyDownHandler ) {\n event = $.getEvent( event );\n propagate = tracker.keyDownHandler(\n {\n eventSource: tracker,\n keyCode: event.keyCode ? event.keyCode : event.charCode,\n ctrl: event.ctrlKey,\n shift: event.shiftKey,\n alt: event.altKey,\n meta: event.metaKey,\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( !propagate ) {\n $.cancelEvent( event );\n }\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onKeyUp( tracker, event ) {\n //$.console.log( \"keyup %s %s %s %s %s\", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey );\n var propagate;\n if ( tracker.keyUpHandler ) {\n event = $.getEvent( event );\n propagate = tracker.keyUpHandler(\n {\n eventSource: tracker,\n keyCode: event.keyCode ? event.keyCode : event.charCode,\n ctrl: event.ctrlKey,\n shift: event.shiftKey,\n alt: event.altKey,\n meta: event.metaKey,\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( !propagate ) {\n $.cancelEvent( event );\n }\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onKeyPress( tracker, event ) {\n //$.console.log( \"keypress %s %s %s %s %s\", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey );\n var propagate;\n if ( tracker.keyHandler ) {\n event = $.getEvent( event );\n propagate = tracker.keyHandler(\n {\n eventSource: tracker,\n keyCode: event.keyCode ? event.keyCode : event.charCode,\n ctrl: event.ctrlKey,\n shift: event.shiftKey,\n alt: event.altKey,\n meta: event.metaKey,\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( !propagate ) {\n $.cancelEvent( event );\n }\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onFocus( tracker, event ) {\n //console.log( \"focus %s\", event );\n var propagate;\n if ( tracker.focusHandler ) {\n event = $.getEvent( event );\n propagate = tracker.focusHandler(\n {\n eventSource: tracker,\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onBlur( tracker, event ) {\n //console.log( \"blur %s\", event );\n var propagate;\n if ( tracker.blurHandler ) {\n event = $.getEvent( event );\n propagate = tracker.blurHandler(\n {\n eventSource: tracker,\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n }\n\n\n /**\n * Handler for 'wheel' events\n *\n * @private\n * @inner\n */\n function onWheel( tracker, event ) {\n handleWheelEvent( tracker, event, event );\n }\n\n\n /**\n * Handler for 'mousewheel', 'DOMMouseScroll', and 'MozMousePixelScroll' events\n *\n * @private\n * @inner\n */\n function onMouseWheel( tracker, event ) {\n event = $.getEvent( event );\n\n // Simulate a 'wheel' event\n var simulatedEvent = {\n target: event.target || event.srcElement,\n type: \"wheel\",\n shiftKey: event.shiftKey || false,\n clientX: event.clientX,\n clientY: event.clientY,\n pageX: event.pageX ? event.pageX : event.clientX,\n pageY: event.pageY ? event.pageY : event.clientY,\n deltaMode: event.type == \"MozMousePixelScroll\" ? 0 : 1, // 0=pixel, 1=line, 2=page\n deltaX: 0,\n deltaZ: 0\n };\n\n // Calculate deltaY\n if ( $.MouseTracker.wheelEventName == \"mousewheel\" ) {\n simulatedEvent.deltaY = -event.wheelDelta / $.DEFAULT_SETTINGS.pixelsPerWheelLine;\n } else {\n simulatedEvent.deltaY = event.detail;\n }\n\n handleWheelEvent( tracker, simulatedEvent, event );\n }\n\n\n /**\n * Handles 'wheel' events.\n * The event may be simulated by the legacy mouse wheel event handler (onMouseWheel()).\n *\n * @private\n * @inner\n */\n function handleWheelEvent( tracker, event, originalEvent ) {\n var nDelta = 0,\n propagate;\n\n // The nDelta variable is gated to provide smooth z-index scrolling\n // since the mouse wheel allows for substantial deltas meant for rapid\n // y-index scrolling.\n // event.deltaMode: 0=pixel, 1=line, 2=page\n // TODO: Deltas in pixel mode should be accumulated then a scroll value computed after $.DEFAULT_SETTINGS.pixelsPerWheelLine threshold reached\n nDelta = event.deltaY < 0 ? 1 : -1;\n\n if ( tracker.scrollHandler ) {\n propagate = tracker.scrollHandler(\n {\n eventSource: tracker,\n pointerType: 'mouse',\n position: getMouseRelative( event, tracker.element ),\n scroll: nDelta,\n shift: event.shiftKey,\n isTouchEvent: false,\n originalEvent: originalEvent,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( originalEvent );\n }\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function isParentChild( parent, child )\n {\n if ( parent === child ) {\n return false;\n }\n while ( child && child !== parent ) {\n child = child.parentNode;\n }\n return child === parent;\n }\n\n\n /**\n * Only used on IE 8\n *\n * @private\n * @inner\n */\n function onMouseEnter( tracker, event ) {\n event = $.getEvent( event );\n\n handleMouseEnter( tracker, event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onMouseOver( tracker, event ) {\n event = $.getEvent( event );\n\n if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) {\n return;\n }\n\n handleMouseEnter( tracker, event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handleMouseEnter( tracker, event ) {\n var gPoint = {\n id: $.MouseTracker.mousePointerId,\n type: 'mouse',\n isPrimary: true,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n updatePointersEnter( tracker, event, [ gPoint ] );\n }\n\n\n /**\n * Only used on IE 8\n *\n * @private\n * @inner\n */\n function onMouseLeave( tracker, event ) {\n event = $.getEvent( event );\n\n handleMouseExit( tracker, event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onMouseOut( tracker, event ) {\n event = $.getEvent( event );\n\n if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) {\n return;\n }\n\n handleMouseExit( tracker, event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handleMouseExit( tracker, event ) {\n var gPoint = {\n id: $.MouseTracker.mousePointerId,\n type: 'mouse',\n isPrimary: true,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n updatePointersExit( tracker, event, [ gPoint ] );\n }\n\n\n /**\n * Returns a W3C DOM level 3 standard button value given an event.button property:\n * -1 == none, 0 == primary/left, 1 == middle, 2 == secondary/right, 3 == X1/back, 4 == X2/forward, 5 == eraser (pen)\n * @private\n * @inner\n */\n function getStandardizedButton( button ) {\n if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {\n // On IE 8, 0 == none, 1 == left, 2 == right, 3 == left and right, 4 == middle, 5 == left and middle, 6 == right and middle, 7 == all three\n // TODO: Support chorded (multiple) button presses on IE 8?\n if ( button === 1 ) {\n return 0;\n } else if ( button === 2 ) {\n return 2;\n } else if ( button === 4 ) {\n return 1;\n } else {\n return -1;\n }\n } else {\n return button;\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onMouseDown( tracker, event ) {\n var gPoint;\n\n event = $.getEvent( event );\n\n gPoint = {\n id: $.MouseTracker.mousePointerId,\n type: 'mouse',\n isPrimary: true,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n if ( updatePointersDown( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) {\n $.stopEvent( event );\n capturePointer( tracker, 'mouse' );\n }\n\n if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler ) {\n $.cancelEvent( event );\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onMouseUp( tracker, event ) {\n handleMouseUp( tracker, event );\n }\n\n /**\n * This handler is attached to the window object (on the capture phase) to emulate mouse capture.\n * onMouseUp is still attached to the tracked element, so stop propagation to avoid processing twice.\n *\n * @private\n * @inner\n */\n function onMouseUpCaptured( tracker, event ) {\n handleMouseUp( tracker, event );\n $.stopEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handleMouseUp( tracker, event ) {\n var gPoint;\n\n event = $.getEvent( event );\n\n gPoint = {\n id: $.MouseTracker.mousePointerId,\n type: 'mouse',\n isPrimary: true,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n if ( updatePointersUp( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) {\n releasePointer( tracker, 'mouse' );\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onMouseMove( tracker, event ) {\n handleMouseMove( tracker, event );\n }\n\n\n /**\n * This handler is attached to the window object (on the capture phase) to emulate mouse capture.\n * onMouseMove is still attached to the tracked element, so stop propagation to avoid processing twice.\n *\n * @private\n * @inner\n */\n function onMouseMoveCaptured( tracker, event ) {\n handleMouseMove( tracker, event );\n $.stopEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handleMouseMove( tracker, event ) {\n var gPoint;\n\n event = $.getEvent( event );\n\n gPoint = {\n id: $.MouseTracker.mousePointerId,\n type: 'mouse',\n isPrimary: true,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n updatePointersMove( tracker, event, [ gPoint ] );\n }\n\n\n /**\n * @private\n * @inner\n */\n function abortContacts( tracker, event, pointsList ) {\n var i,\n gPointCount = pointsList.getLength(),\n abortGPoints = [];\n\n // Check contact count for hoverable pointer types before aborting\n if (pointsList.type === 'touch' || pointsList.contacts > 0) {\n for ( i = 0; i < gPointCount; i++ ) {\n abortGPoints.push( pointsList.getByIndex( i ) );\n }\n\n if ( abortGPoints.length > 0 ) {\n // simulate touchend/mouseup\n updatePointersUp( tracker, event, abortGPoints, 0 ); // 0 means primary button press/release or touch contact\n // release pointer capture\n pointsList.captureCount = 1;\n releasePointer( tracker, pointsList.type );\n // simulate touchleave/mouseout\n updatePointersExit( tracker, event, abortGPoints );\n }\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onTouchStart( tracker, event ) {\n var time,\n i,\n j,\n touchCount = event.changedTouches.length,\n gPoints = [],\n parentGPoints,\n pointsList = tracker.getActivePointersListByType( 'touch' );\n\n time = $.now();\n\n if ( pointsList.getLength() > event.touches.length - touchCount ) {\n $.console.warn('Tracked touch contact count doesn\\'t match event.touches.length. Removing all tracked touch pointers.');\n abortContacts( tracker, event, pointsList );\n }\n\n for ( i = 0; i < touchCount; i++ ) {\n gPoints.push( {\n id: event.changedTouches[ i ].identifier,\n type: 'touch',\n // isPrimary not set - let the updatePointers functions determine it\n currentPos: getMouseAbsolute( event.changedTouches[ i ] ),\n currentTime: time\n } );\n }\n\n // simulate touchenter on our tracked element\n updatePointersEnter( tracker, event, gPoints );\n\n // simulate touchenter on our tracked element's tracked ancestor elements\n for ( i = 0; i < MOUSETRACKERS.length; i++ ) {\n if ( MOUSETRACKERS[ i ] !== tracker && MOUSETRACKERS[ i ].isTracking() && isParentChild( MOUSETRACKERS[ i ].element, tracker.element ) ) {\n parentGPoints = [];\n for ( j = 0; j < touchCount; j++ ) {\n parentGPoints.push( {\n id: event.changedTouches[ j ].identifier,\n type: 'touch',\n // isPrimary not set - let the updatePointers functions determine it\n currentPos: getMouseAbsolute( event.changedTouches[ j ] ),\n currentTime: time\n } );\n }\n updatePointersEnter( MOUSETRACKERS[ i ], event, parentGPoints );\n }\n }\n\n if ( updatePointersDown( tracker, event, gPoints, 0 ) ) { // 0 means primary button press/release or touch contact\n $.stopEvent( event );\n capturePointer( tracker, 'touch', touchCount );\n }\n\n $.cancelEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onTouchEnd( tracker, event ) {\n handleTouchEnd( tracker, event );\n }\n\n\n /**\n * This handler is attached to the window object (on the capture phase) to emulate pointer capture.\n * onTouchEnd is still attached to the tracked element, so stop propagation to avoid processing twice.\n *\n * @private\n * @inner\n */\n function onTouchEndCaptured( tracker, event ) {\n handleTouchEnd( tracker, event );\n $.stopEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handleTouchEnd( tracker, event ) {\n var time,\n i,\n j,\n touchCount = event.changedTouches.length,\n gPoints = [],\n parentGPoints;\n\n time = $.now();\n\n for ( i = 0; i < touchCount; i++ ) {\n gPoints.push( {\n id: event.changedTouches[ i ].identifier,\n type: 'touch',\n // isPrimary not set - let the updatePointers functions determine it\n currentPos: getMouseAbsolute( event.changedTouches[ i ] ),\n currentTime: time\n } );\n }\n\n if ( updatePointersUp( tracker, event, gPoints, 0 ) ) {\n releasePointer( tracker, 'touch', touchCount );\n }\n\n // simulate touchleave on our tracked element\n updatePointersExit( tracker, event, gPoints );\n\n // simulate touchleave on our tracked element's tracked ancestor elements\n for ( i = 0; i < MOUSETRACKERS.length; i++ ) {\n if ( MOUSETRACKERS[ i ] !== tracker && MOUSETRACKERS[ i ].isTracking() && isParentChild( MOUSETRACKERS[ i ].element, tracker.element ) ) {\n parentGPoints = [];\n for ( j = 0; j < touchCount; j++ ) {\n parentGPoints.push( {\n id: event.changedTouches[ j ].identifier,\n type: 'touch',\n // isPrimary not set - let the updatePointers functions determine it\n currentPos: getMouseAbsolute( event.changedTouches[ j ] ),\n currentTime: time\n } );\n }\n updatePointersExit( MOUSETRACKERS[ i ], event, parentGPoints );\n }\n }\n\n $.cancelEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onTouchMove( tracker, event ) {\n handleTouchMove( tracker, event );\n }\n\n\n /**\n * This handler is attached to the window object (on the capture phase) to emulate pointer capture.\n * onTouchMove is still attached to the tracked element, so stop propagation to avoid processing twice.\n *\n * @private\n * @inner\n */\n function onTouchMoveCaptured( tracker, event ) {\n handleTouchMove( tracker, event );\n $.stopEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handleTouchMove( tracker, event ) {\n var i,\n touchCount = event.changedTouches.length,\n gPoints = [];\n\n for ( i = 0; i < touchCount; i++ ) {\n gPoints.push( {\n id: event.changedTouches[ i ].identifier,\n type: 'touch',\n // isPrimary not set - let the updatePointers functions determine it\n currentPos: getMouseAbsolute( event.changedTouches[ i ] ),\n currentTime: $.now()\n } );\n }\n\n updatePointersMove( tracker, event, gPoints );\n\n $.cancelEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onTouchCancel( tracker, event ) {\n var pointsList = tracker.getActivePointersListByType('touch');\n\n abortContacts( tracker, event, pointsList );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onGestureStart( tracker, event ) {\n event.stopPropagation();\n event.preventDefault();\n return false;\n }\n\n\n /**\n * @private\n * @inner\n */\n function onGestureChange( tracker, event ) {\n event.stopPropagation();\n event.preventDefault();\n return false;\n }\n\n\n /**\n * @private\n * @inner\n */\n function onPointerOver( tracker, event ) {\n var gPoint;\n\n if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) {\n return;\n }\n\n gPoint = {\n id: event.pointerId,\n type: getPointerType( event ),\n isPrimary: event.isPrimary,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n updatePointersEnter( tracker, event, [ gPoint ] );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onPointerOut( tracker, event ) {\n var gPoint;\n\n if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) {\n return;\n }\n\n gPoint = {\n id: event.pointerId,\n type: getPointerType( event ),\n isPrimary: event.isPrimary,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n updatePointersExit( tracker, event, [ gPoint ] );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onPointerDown( tracker, event ) {\n var gPoint;\n\n gPoint = {\n id: event.pointerId,\n type: getPointerType( event ),\n isPrimary: event.isPrimary,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) {\n $.stopEvent( event );\n capturePointer( tracker, gPoint.type );\n }\n\n if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {\n $.cancelEvent( event );\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onPointerUp( tracker, event ) {\n handlePointerUp( tracker, event );\n }\n\n\n /**\n * This handler is attached to the window object (on the capture phase) to emulate mouse capture.\n * onPointerUp is still attached to the tracked element, so stop propagation to avoid processing twice.\n *\n * @private\n * @inner\n */\n function onPointerUpCaptured( tracker, event ) {\n var pointsList = tracker.getActivePointersListByType( getPointerType( event ) );\n if ( pointsList.getById( event.pointerId ) ) {\n handlePointerUp( tracker, event );\n }\n $.stopEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handlePointerUp( tracker, event ) {\n var gPoint;\n\n gPoint = {\n id: event.pointerId,\n type: getPointerType( event ),\n isPrimary: event.isPrimary,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) {\n releasePointer( tracker, gPoint.type );\n }\n }\n\n\n /**\n * @private\n * @inner\n */\n function onPointerMove( tracker, event ) {\n handlePointerMove( tracker, event );\n }\n\n\n /**\n * This handler is attached to the window object (on the capture phase) to emulate mouse capture.\n * onPointerMove is still attached to the tracked element, so stop propagation to avoid processing twice.\n *\n * @private\n * @inner\n */\n function onPointerMoveCaptured( tracker, event ) {\n var pointsList = tracker.getActivePointersListByType( getPointerType( event ) );\n if ( pointsList.getById( event.pointerId ) ) {\n handlePointerMove( tracker, event );\n }\n $.stopEvent( event );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handlePointerMove( tracker, event ) {\n // Pointer changed coordinates, button state, pressure, tilt, or contact geometry (e.g. width and height)\n var gPoint;\n\n gPoint = {\n id: event.pointerId,\n type: getPointerType( event ),\n isPrimary: event.isPrimary,\n currentPos: getMouseAbsolute( event ),\n currentTime: $.now()\n };\n\n updatePointersMove( tracker, event, [ gPoint ] );\n }\n\n\n /**\n * @private\n * @inner\n */\n function onPointerCancel( tracker, event ) {\n var gPoint;\n\n gPoint = {\n id: event.pointerId,\n type: getPointerType( event )\n };\n\n updatePointersCancel( tracker, event, [ gPoint ] );\n }\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Device-agnostic DOM event handlers\n///////////////////////////////////////////////////////////////////////////////\n\n /**\n * @function\n * @private\n * @inner\n * @param {OpenSeadragon.MouseTracker.GesturePointList} pointsList\n * The GesturePointList to track the pointer in.\n * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint\n * Gesture point to track.\n * @returns {Number} Number of gesture points in pointsList.\n */\n function startTrackingPointer( pointsList, gPoint ) {\n\n // If isPrimary is not known for the pointer then set it according to our rules:\n // true if the first pointer in the gesture, otherwise false\n if ( !gPoint.hasOwnProperty( 'isPrimary' ) ) {\n if ( pointsList.getLength() === 0 ) {\n gPoint.isPrimary = true;\n } else {\n gPoint.isPrimary = false;\n }\n }\n gPoint.speed = 0;\n gPoint.direction = 0;\n gPoint.contactPos = gPoint.currentPos;\n gPoint.contactTime = gPoint.currentTime;\n gPoint.lastPos = gPoint.currentPos;\n gPoint.lastTime = gPoint.currentTime;\n\n return pointsList.add( gPoint );\n }\n\n\n /**\n * @function\n * @private\n * @inner\n * @param {OpenSeadragon.MouseTracker.GesturePointList} pointsList\n * The GesturePointList to stop tracking the pointer on.\n * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint\n * Gesture point to stop tracking.\n * @returns {Number} Number of gesture points in pointsList.\n */\n function stopTrackingPointer( pointsList, gPoint ) {\n var listLength,\n primaryPoint;\n\n if ( pointsList.getById( gPoint.id ) ) {\n listLength = pointsList.removeById( gPoint.id );\n\n // If isPrimary is not known for the pointer and we just removed the primary pointer from the list then we need to set another pointer as primary\n if ( !gPoint.hasOwnProperty( 'isPrimary' ) ) {\n primaryPoint = pointsList.getPrimary();\n if ( !primaryPoint ) {\n primaryPoint = pointsList.getByIndex( 0 );\n if ( primaryPoint ) {\n primaryPoint.isPrimary = true;\n }\n }\n }\n } else {\n listLength = pointsList.getLength();\n }\n\n return listLength;\n }\n\n\n /**\n * @function\n * @private\n * @inner\n * @param {OpenSeadragon.MouseTracker} tracker\n * A reference to the MouseTracker instance.\n * @param {Object} event\n * A reference to the originating DOM event.\n * @param {Array.} gPoints\n * Gesture points associated with the event.\n */\n function updatePointersEnter( tracker, event, gPoints ) {\n var pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),\n i,\n gPointCount = gPoints.length,\n curGPoint,\n updateGPoint,\n propagate;\n\n for ( i = 0; i < gPointCount; i++ ) {\n curGPoint = gPoints[ i ];\n updateGPoint = pointsList.getById( curGPoint.id );\n\n if ( updateGPoint ) {\n // Already tracking the pointer...update it\n updateGPoint.insideElement = true;\n updateGPoint.lastPos = updateGPoint.currentPos;\n updateGPoint.lastTime = updateGPoint.currentTime;\n updateGPoint.currentPos = curGPoint.currentPos;\n updateGPoint.currentTime = curGPoint.currentTime;\n\n curGPoint = updateGPoint;\n } else {\n // Initialize for tracking and add to the tracking list\n curGPoint.captured = false;\n curGPoint.insideElementPressed = false;\n curGPoint.insideElement = true;\n startTrackingPointer( pointsList, curGPoint );\n }\n\n // Enter\n if ( tracker.enterHandler ) {\n propagate = tracker.enterHandler(\n {\n eventSource: tracker,\n pointerType: curGPoint.type,\n position: getPointRelativeToAbsolute( curGPoint.currentPos, tracker.element ),\n buttons: pointsList.buttons,\n pointers: tracker.getActivePointerCount(),\n insideElementPressed: curGPoint.insideElementPressed,\n buttonDownAny: pointsList.buttons !== 0,\n isTouchEvent: curGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n }\n }\n\n\n /**\n * @function\n * @private\n * @inner\n * @param {OpenSeadragon.MouseTracker} tracker\n * A reference to the MouseTracker instance.\n * @param {Object} event\n * A reference to the originating DOM event.\n * @param {Array.} gPoints\n * Gesture points associated with the event.\n */\n function updatePointersExit( tracker, event, gPoints ) {\n var pointsList = tracker.getActivePointersListByType(gPoints[0].type),\n i,\n gPointCount = gPoints.length,\n curGPoint,\n updateGPoint,\n propagate;\n\n for ( i = 0; i < gPointCount; i++ ) {\n curGPoint = gPoints[ i ];\n updateGPoint = pointsList.getById( curGPoint.id );\n\n if ( updateGPoint ) {\n // Already tracking the pointer. If captured then update it, else stop tracking it\n if ( updateGPoint.captured ) {\n updateGPoint.insideElement = false;\n updateGPoint.lastPos = updateGPoint.currentPos;\n updateGPoint.lastTime = updateGPoint.currentTime;\n updateGPoint.currentPos = curGPoint.currentPos;\n updateGPoint.currentTime = curGPoint.currentTime;\n } else {\n stopTrackingPointer( pointsList, updateGPoint );\n }\n\n curGPoint = updateGPoint;\n }\n\n // Exit\n if ( tracker.exitHandler ) {\n propagate = tracker.exitHandler(\n {\n eventSource: tracker,\n pointerType: curGPoint.type,\n position: getPointRelativeToAbsolute( curGPoint.currentPos, tracker.element ),\n buttons: pointsList.buttons,\n pointers: tracker.getActivePointerCount(),\n insideElementPressed: updateGPoint ? updateGPoint.insideElementPressed : false,\n buttonDownAny: pointsList.buttons !== 0,\n isTouchEvent: curGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n }\n }\n\n\n /**\n * @function\n * @private\n * @inner\n * @param {OpenSeadragon.MouseTracker} tracker\n * A reference to the MouseTracker instance.\n * @param {Object} event\n * A reference to the originating DOM event.\n * @param {Array.} gPoints\n * Gesture points associated with the event.\n * @param {Number} buttonChanged\n * The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.\n * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model,\n * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events.\n *\n * @returns {Boolean} True if pointers should be captured to the tracked element, otherwise false.\n */\n function updatePointersDown( tracker, event, gPoints, buttonChanged ) {\n var delegate = THIS[ tracker.hash ],\n propagate,\n pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),\n i,\n gPointCount = gPoints.length,\n curGPoint,\n updateGPoint;\n\n if ( typeof event.buttons !== 'undefined' ) {\n pointsList.buttons = event.buttons;\n } else {\n if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {\n if ( buttonChanged === 0 ) {\n // Primary\n pointsList.buttons += 1;\n } else if ( buttonChanged === 1 ) {\n // Aux\n pointsList.buttons += 4;\n } else if ( buttonChanged === 2 ) {\n // Secondary\n pointsList.buttons += 2;\n } else if ( buttonChanged === 3 ) {\n // X1 (Back)\n pointsList.buttons += 8;\n } else if ( buttonChanged === 4 ) {\n // X2 (Forward)\n pointsList.buttons += 16;\n } else if ( buttonChanged === 5 ) {\n // Pen Eraser\n pointsList.buttons += 32;\n }\n } else {\n if ( buttonChanged === 0 ) {\n // Primary\n pointsList.buttons |= 1;\n } else if ( buttonChanged === 1 ) {\n // Aux\n pointsList.buttons |= 4;\n } else if ( buttonChanged === 2 ) {\n // Secondary\n pointsList.buttons |= 2;\n } else if ( buttonChanged === 3 ) {\n // X1 (Back)\n pointsList.buttons |= 8;\n } else if ( buttonChanged === 4 ) {\n // X2 (Forward)\n pointsList.buttons |= 16;\n } else if ( buttonChanged === 5 ) {\n // Pen Eraser\n pointsList.buttons |= 32;\n }\n }\n }\n\n // Some pointers may steal control from another pointer without firing the appropriate release events\n // e.g. Touching a screen while click-dragging with certain mice.\n var otherPointsLists = tracker.getActivePointersListsExceptType(gPoints[ 0 ].type);\n for (i = 0; i < otherPointsLists.length; i++) {\n //If another pointer has contact, simulate the release\n abortContacts(tracker, event, otherPointsLists[i]); // No-op if no active pointer\n }\n\n // Only capture and track primary button, pen, and touch contacts\n if ( buttonChanged !== 0 ) {\n // Aux Press\n if ( tracker.nonPrimaryPressHandler ) {\n propagate = tracker.nonPrimaryPressHandler(\n {\n eventSource: tracker,\n pointerType: gPoints[ 0 ].type,\n position: getPointRelativeToAbsolute( gPoints[ 0 ].currentPos, tracker.element ),\n button: buttonChanged,\n buttons: pointsList.buttons,\n isTouchEvent: gPoints[ 0 ].type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n\n return false;\n }\n\n for ( i = 0; i < gPointCount; i++ ) {\n curGPoint = gPoints[ i ];\n updateGPoint = pointsList.getById( curGPoint.id );\n\n if ( updateGPoint ) {\n // Already tracking the pointer...update it\n updateGPoint.captured = true;\n updateGPoint.insideElementPressed = true;\n updateGPoint.insideElement = true;\n updateGPoint.contactPos = curGPoint.currentPos;\n updateGPoint.contactTime = curGPoint.currentTime;\n updateGPoint.lastPos = updateGPoint.currentPos;\n updateGPoint.lastTime = updateGPoint.currentTime;\n updateGPoint.currentPos = curGPoint.currentPos;\n updateGPoint.currentTime = curGPoint.currentTime;\n\n curGPoint = updateGPoint;\n } else {\n // Initialize for tracking and add to the tracking list (no pointerover or pointermove event occurred before this)\n curGPoint.captured = true;\n curGPoint.insideElementPressed = true;\n curGPoint.insideElement = true;\n startTrackingPointer( pointsList, curGPoint );\n }\n\n pointsList.addContact();\n //$.console.log('contacts++ ', pointsList.contacts);\n\n if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {\n $.MouseTracker.gesturePointVelocityTracker.addPoint( tracker, curGPoint );\n }\n\n if ( pointsList.contacts === 1 ) {\n // Press\n if ( tracker.pressHandler ) {\n propagate = tracker.pressHandler(\n {\n eventSource: tracker,\n pointerType: curGPoint.type,\n position: getPointRelativeToAbsolute( curGPoint.contactPos, tracker.element ),\n buttons: pointsList.buttons,\n isTouchEvent: curGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n } else if ( pointsList.contacts === 2 ) {\n if ( tracker.pinchHandler && curGPoint.type === 'touch' ) {\n // Initialize for pinch\n delegate.pinchGPoints = pointsList.asArray();\n delegate.lastPinchDist = delegate.currentPinchDist = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos );\n delegate.lastPinchCenter = delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos );\n }\n }\n }\n\n return true;\n }\n\n\n /**\n * @function\n * @private\n * @inner\n * @param {OpenSeadragon.MouseTracker} tracker\n * A reference to the MouseTracker instance.\n * @param {Object} event\n * A reference to the originating DOM event.\n * @param {Array.} gPoints\n * Gesture points associated with the event.\n * @param {Number} buttonChanged\n * The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.\n * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model,\n * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events.\n *\n * @returns {Boolean} True if pointer capture should be released from the tracked element, otherwise false.\n */\n function updatePointersUp( tracker, event, gPoints, buttonChanged ) {\n var delegate = THIS[ tracker.hash ],\n pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),\n propagate,\n releasePoint,\n releaseTime,\n i,\n gPointCount = gPoints.length,\n curGPoint,\n updateGPoint,\n releaseCapture = false,\n wasCaptured = false,\n quick;\n\n if ( typeof event.buttons !== 'undefined' ) {\n pointsList.buttons = event.buttons;\n } else {\n if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {\n if ( buttonChanged === 0 ) {\n // Primary\n pointsList.buttons -= 1;\n } else if ( buttonChanged === 1 ) {\n // Aux\n pointsList.buttons -= 4;\n } else if ( buttonChanged === 2 ) {\n // Secondary\n pointsList.buttons -= 2;\n } else if ( buttonChanged === 3 ) {\n // X1 (Back)\n pointsList.buttons -= 8;\n } else if ( buttonChanged === 4 ) {\n // X2 (Forward)\n pointsList.buttons -= 16;\n } else if ( buttonChanged === 5 ) {\n // Pen Eraser\n pointsList.buttons -= 32;\n }\n } else {\n if ( buttonChanged === 0 ) {\n // Primary\n pointsList.buttons ^= ~1;\n } else if ( buttonChanged === 1 ) {\n // Aux\n pointsList.buttons ^= ~4;\n } else if ( buttonChanged === 2 ) {\n // Secondary\n pointsList.buttons ^= ~2;\n } else if ( buttonChanged === 3 ) {\n // X1 (Back)\n pointsList.buttons ^= ~8;\n } else if ( buttonChanged === 4 ) {\n // X2 (Forward)\n pointsList.buttons ^= ~16;\n } else if ( buttonChanged === 5 ) {\n // Pen Eraser\n pointsList.buttons ^= ~32;\n }\n }\n }\n\n // Only capture and track primary button, pen, and touch contacts\n if ( buttonChanged !== 0 ) {\n // Aux Release\n if ( tracker.nonPrimaryReleaseHandler ) {\n propagate = tracker.nonPrimaryReleaseHandler(\n {\n eventSource: tracker,\n pointerType: gPoints[ 0 ].type,\n position: getPointRelativeToAbsolute(gPoints[0].currentPos, tracker.element),\n button: buttonChanged,\n buttons: pointsList.buttons,\n isTouchEvent: gPoints[ 0 ].type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n\n // A primary mouse button may have been released while the non-primary button was down\n var otherPointsList = tracker.getActivePointersListByType(\"mouse\");\n // Stop tracking the mouse; see https://github.com/openseadragon/openseadragon/pull/1223\n abortContacts(tracker, event, otherPointsList); // No-op if no active pointer\n\n return false;\n }\n\n for ( i = 0; i < gPointCount; i++ ) {\n curGPoint = gPoints[ i ];\n updateGPoint = pointsList.getById( curGPoint.id );\n\n if ( updateGPoint ) {\n // Update the pointer, stop tracking it if not still in this element\n if ( updateGPoint.captured ) {\n updateGPoint.captured = false;\n releaseCapture = true;\n wasCaptured = true;\n }\n updateGPoint.lastPos = updateGPoint.currentPos;\n updateGPoint.lastTime = updateGPoint.currentTime;\n updateGPoint.currentPos = curGPoint.currentPos;\n updateGPoint.currentTime = curGPoint.currentTime;\n if ( !updateGPoint.insideElement ) {\n stopTrackingPointer( pointsList, updateGPoint );\n }\n\n releasePoint = updateGPoint.currentPos;\n releaseTime = updateGPoint.currentTime;\n\n if ( wasCaptured ) {\n // Pointer was activated in our element but could have been removed in any element since events are captured to our element\n\n pointsList.removeContact();\n //$.console.log('contacts-- ', pointsList.contacts);\n\n if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {\n $.MouseTracker.gesturePointVelocityTracker.removePoint( tracker, updateGPoint );\n }\n\n if ( pointsList.contacts === 0 ) {\n\n // Release (pressed in our element)\n if ( tracker.releaseHandler ) {\n propagate = tracker.releaseHandler(\n {\n eventSource: tracker,\n pointerType: updateGPoint.type,\n position: getPointRelativeToAbsolute( releasePoint, tracker.element ),\n buttons: pointsList.buttons,\n insideElementPressed: updateGPoint.insideElementPressed,\n insideElementReleased: updateGPoint.insideElement,\n isTouchEvent: updateGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n\n // Drag End\n if ( tracker.dragEndHandler && !updateGPoint.currentPos.equals( updateGPoint.contactPos ) ) {\n propagate = tracker.dragEndHandler(\n {\n eventSource: tracker,\n pointerType: updateGPoint.type,\n position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),\n speed: updateGPoint.speed,\n direction: updateGPoint.direction,\n shift: event.shiftKey,\n isTouchEvent: updateGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n\n // Click / Double-Click\n if ( ( tracker.clickHandler || tracker.dblClickHandler ) && updateGPoint.insideElement ) {\n quick = releaseTime - updateGPoint.contactTime <= tracker.clickTimeThreshold &&\n updateGPoint.contactPos.distanceTo( releasePoint ) <= tracker.clickDistThreshold;\n\n // Click\n if ( tracker.clickHandler ) {\n propagate = tracker.clickHandler(\n {\n eventSource: tracker,\n pointerType: updateGPoint.type,\n position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),\n quick: quick,\n shift: event.shiftKey,\n isTouchEvent: updateGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n\n // Double-Click\n if ( tracker.dblClickHandler && quick ) {\n pointsList.clicks++;\n if ( pointsList.clicks === 1 ) {\n delegate.lastClickPos = releasePoint;\n /*jshint loopfunc:true*/\n delegate.dblClickTimeOut = setTimeout( function() {\n pointsList.clicks = 0;\n }, tracker.dblClickTimeThreshold );\n /*jshint loopfunc:false*/\n } else if ( pointsList.clicks === 2 ) {\n clearTimeout( delegate.dblClickTimeOut );\n pointsList.clicks = 0;\n if ( delegate.lastClickPos.distanceTo( releasePoint ) <= tracker.dblClickDistThreshold ) {\n propagate = tracker.dblClickHandler(\n {\n eventSource: tracker,\n pointerType: updateGPoint.type,\n position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),\n shift: event.shiftKey,\n isTouchEvent: updateGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n delegate.lastClickPos = null;\n }\n }\n }\n } else if ( pointsList.contacts === 2 ) {\n if ( tracker.pinchHandler && updateGPoint.type === 'touch' ) {\n // Reset for pinch\n delegate.pinchGPoints = pointsList.asArray();\n delegate.lastPinchDist = delegate.currentPinchDist = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos );\n delegate.lastPinchCenter = delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos );\n }\n }\n } else {\n // Pointer was activated in another element but removed in our element\n\n // Release (pressed in another element)\n if ( tracker.releaseHandler ) {\n propagate = tracker.releaseHandler(\n {\n eventSource: tracker,\n pointerType: updateGPoint.type,\n position: getPointRelativeToAbsolute( releasePoint, tracker.element ),\n buttons: pointsList.buttons,\n insideElementPressed: updateGPoint.insideElementPressed,\n insideElementReleased: updateGPoint.insideElement,\n isTouchEvent: updateGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n }\n }\n }\n\n return releaseCapture;\n }\n\n\n /**\n * Call when pointer(s) change coordinates, button state, pressure, tilt, or contact geometry (e.g. width and height)\n *\n * @function\n * @private\n * @inner\n * @param {OpenSeadragon.MouseTracker} tracker\n * A reference to the MouseTracker instance.\n * @param {Object} event\n * A reference to the originating DOM event.\n * @param {Array.} gPoints\n * Gesture points associated with the event.\n */\n function updatePointersMove( tracker, event, gPoints ) {\n var delegate = THIS[ tracker.hash ],\n pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),\n i,\n gPointCount = gPoints.length,\n curGPoint,\n updateGPoint,\n gPointArray,\n delta,\n propagate;\n\n if ( typeof event.buttons !== 'undefined' ) {\n pointsList.buttons = event.buttons;\n }\n\n for ( i = 0; i < gPointCount; i++ ) {\n curGPoint = gPoints[ i ];\n updateGPoint = pointsList.getById( curGPoint.id );\n\n if ( updateGPoint ) {\n // Already tracking the pointer...update it\n if ( curGPoint.hasOwnProperty( 'isPrimary' ) ) {\n updateGPoint.isPrimary = curGPoint.isPrimary;\n }\n updateGPoint.lastPos = updateGPoint.currentPos;\n updateGPoint.lastTime = updateGPoint.currentTime;\n updateGPoint.currentPos = curGPoint.currentPos;\n updateGPoint.currentTime = curGPoint.currentTime;\n } else {\n // Initialize for tracking and add to the tracking list (no pointerover or pointerdown event occurred before this)\n curGPoint.captured = false;\n curGPoint.insideElementPressed = false;\n curGPoint.insideElement = true;\n startTrackingPointer( pointsList, curGPoint );\n }\n }\n\n // Stop (mouse only)\n if ( tracker.stopHandler && gPoints[ 0 ].type === 'mouse' ) {\n clearTimeout( tracker.stopTimeOut );\n tracker.stopTimeOut = setTimeout( function() {\n handlePointerStop( tracker, event, gPoints[ 0 ].type );\n }, tracker.stopDelay );\n }\n\n if ( pointsList.contacts === 0 ) {\n // Move (no contacts: hovering mouse or other hover-capable device)\n if ( tracker.moveHandler ) {\n propagate = tracker.moveHandler(\n {\n eventSource: tracker,\n pointerType: gPoints[ 0 ].type,\n position: getPointRelativeToAbsolute( gPoints[ 0 ].currentPos, tracker.element ),\n buttons: pointsList.buttons,\n isTouchEvent: gPoints[ 0 ].type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n } else if ( pointsList.contacts === 1 ) {\n // Move (1 contact)\n if ( tracker.moveHandler ) {\n updateGPoint = pointsList.asArray()[ 0 ];\n propagate = tracker.moveHandler(\n {\n eventSource: tracker,\n pointerType: updateGPoint.type,\n position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),\n buttons: pointsList.buttons,\n isTouchEvent: updateGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n\n // Drag\n if ( tracker.dragHandler ) {\n updateGPoint = pointsList.asArray()[ 0 ];\n delta = updateGPoint.currentPos.minus( updateGPoint.lastPos );\n propagate = tracker.dragHandler(\n {\n eventSource: tracker,\n pointerType: updateGPoint.type,\n position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),\n buttons: pointsList.buttons,\n delta: delta,\n speed: updateGPoint.speed,\n direction: updateGPoint.direction,\n shift: event.shiftKey,\n isTouchEvent: updateGPoint.type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n } else if ( pointsList.contacts === 2 ) {\n // Move (2 contacts, use center)\n if ( tracker.moveHandler ) {\n gPointArray = pointsList.asArray();\n propagate = tracker.moveHandler(\n {\n eventSource: tracker,\n pointerType: gPointArray[ 0 ].type,\n position: getPointRelativeToAbsolute( getCenterPoint( gPointArray[ 0 ].currentPos, gPointArray[ 1 ].currentPos ), tracker.element ),\n buttons: pointsList.buttons,\n isTouchEvent: gPointArray[ 0 ].type === 'touch',\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n\n // Pinch\n if ( tracker.pinchHandler && gPoints[ 0 ].type === 'touch' ) {\n delta = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos );\n if ( delta != delegate.currentPinchDist ) {\n delegate.lastPinchDist = delegate.currentPinchDist;\n delegate.currentPinchDist = delta;\n delegate.lastPinchCenter = delegate.currentPinchCenter;\n delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos );\n propagate = tracker.pinchHandler(\n {\n eventSource: tracker,\n pointerType: 'touch',\n gesturePoints: delegate.pinchGPoints,\n lastCenter: getPointRelativeToAbsolute( delegate.lastPinchCenter, tracker.element ),\n center: getPointRelativeToAbsolute( delegate.currentPinchCenter, tracker.element ),\n lastDistance: delegate.lastPinchDist,\n distance: delegate.currentPinchDist,\n shift: event.shiftKey,\n originalEvent: event,\n preventDefaultAction: false,\n userData: tracker.userData\n }\n );\n if ( propagate === false ) {\n $.cancelEvent( event );\n }\n }\n }\n }\n }\n\n\n /**\n * @function\n * @private\n * @inner\n * @param {OpenSeadragon.MouseTracker} tracker\n * A reference to the MouseTracker instance.\n * @param {Object} event\n * A reference to the originating DOM event.\n * @param {Array.} gPoints\n * Gesture points associated with the event.\n */\n function updatePointersCancel( tracker, event, gPoints ) {\n updatePointersUp( tracker, event, gPoints, 0 );\n updatePointersExit( tracker, event, gPoints );\n }\n\n\n /**\n * @private\n * @inner\n */\n function handlePointerStop( tracker, originalMoveEvent, pointerType ) {\n if ( tracker.stopHandler ) {\n tracker.stopHandler( {\n eventSource: tracker,\n pointerType: pointerType,\n position: getMouseRelative( originalMoveEvent, tracker.element ),\n buttons: tracker.getActivePointersListByType( pointerType ).buttons,\n isTouchEvent: pointerType === 'touch',\n originalEvent: originalMoveEvent,\n preventDefaultAction: false,\n userData: tracker.userData\n } );\n }\n }\n\n /**\n * True if inside an iframe, otherwise false.\n * @member {Boolean} isInIframe\n * @private\n * @inner\n */\n var isInIframe = (function() {\n try {\n return window.self !== window.top;\n } catch (e) {\n return true;\n }\n })();\n\n /**\n * @function\n * @private\n * @inner\n * @returns {Boolean} True if the target has access rights to events, otherwise false.\n */\n function canAccessEvents (target) {\n try {\n return target.addEventListener && target.removeEventListener;\n } catch (e) {\n return false;\n }\n }\n\n}(OpenSeadragon));\n","/*\n * OpenSeadragon - Control\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * An enumeration of supported locations where controls can be anchored.\n * The anchoring is always relative to the container.\n * @member ControlAnchor\n * @memberof OpenSeadragon\n * @static\n * @type {Object}\n * @property {Number} NONE\n * @property {Number} TOP_LEFT\n * @property {Number} TOP_RIGHT\n * @property {Number} BOTTOM_LEFT\n * @property {Number} BOTTOM_RIGHT\n * @property {Number} ABSOLUTE\n */\n$.ControlAnchor = {\n NONE: 0,\n TOP_LEFT: 1,\n TOP_RIGHT: 2,\n BOTTOM_RIGHT: 3,\n BOTTOM_LEFT: 4,\n ABSOLUTE: 5\n};\n\n/**\n * @class Control\n * @classdesc A Control represents any interface element which is meant to allow the user\n * to interact with the zoomable interface. Any control can be anchored to any\n * element.\n *\n * @memberof OpenSeadragon\n * @param {Element} element - the control element to be anchored in the container.\n * @param {Object } options - All required and optional settings for configuring a control element.\n * @param {OpenSeadragon.ControlAnchor} [options.anchor=OpenSeadragon.ControlAnchor.NONE] - the position of the control\n * relative to the container.\n * @param {Boolean} [options.attachToViewer=true] - Whether the control should be added directly to the viewer, or\n * directly to the container\n * @param {Boolean} [options.autoFade=true] - Whether the control should have the autofade behavior\n * @param {Element} container - the element to control will be anchored too.\n */\n$.Control = function ( element, options, container ) {\n var parent = element.parentNode;\n if (typeof options === 'number')\n {\n $.console.error(\"Passing an anchor directly into the OpenSeadragon.Control constructor is deprecated; \" +\n \"please use an options object instead. \" +\n \"Support for this deprecated variant is scheduled for removal in December 2013\");\n options = {anchor: options};\n }\n options.attachToViewer = (typeof options.attachToViewer === 'undefined') ? true : options.attachToViewer;\n /**\n * True if the control should have autofade behavior.\n * @member {Boolean} autoFade\n * @memberof OpenSeadragon.Control#\n */\n this.autoFade = (typeof options.autoFade === 'undefined') ? true : options.autoFade;\n /**\n * The element providing the user interface with some type of control (e.g. a zoom-in button).\n * @member {Element} element\n * @memberof OpenSeadragon.Control#\n */\n this.element = element;\n /**\n * The position of the Control relative to its container.\n * @member {OpenSeadragon.ControlAnchor} anchor\n * @memberof OpenSeadragon.Control#\n */\n this.anchor = options.anchor;\n /**\n * The Control's containing element.\n * @member {Element} container\n * @memberof OpenSeadragon.Control#\n */\n this.container = container;\n /**\n * A neutral element surrounding the control element.\n * @member {Element} wrapper\n * @memberof OpenSeadragon.Control#\n */\n if ( this.anchor == $.ControlAnchor.ABSOLUTE ) {\n this.wrapper = $.makeNeutralElement( \"div\" );\n this.wrapper.style.position = \"absolute\";\n this.wrapper.style.top = typeof (options.top) == \"number\" ? (options.top + 'px') : options.top;\n this.wrapper.style.left = typeof (options.left) == \"number\" ? (options.left + 'px') : options.left;\n this.wrapper.style.height = typeof (options.height) == \"number\" ? (options.height + 'px') : options.height;\n this.wrapper.style.width = typeof (options.width) == \"number\" ? (options.width + 'px') : options.width;\n this.wrapper.style.margin = \"0px\";\n this.wrapper.style.padding = \"0px\";\n\n this.element.style.position = \"relative\";\n this.element.style.top = \"0px\";\n this.element.style.left = \"0px\";\n this.element.style.height = \"100%\";\n this.element.style.width = \"100%\";\n } else {\n this.wrapper = $.makeNeutralElement( \"div\" );\n this.wrapper.style.display = \"inline-block\";\n if ( this.anchor == $.ControlAnchor.NONE ) {\n // IE6 fix\n this.wrapper.style.width = this.wrapper.style.height = \"100%\";\n }\n }\n this.wrapper.appendChild( this.element );\n\n if (options.attachToViewer ) {\n if ( this.anchor == $.ControlAnchor.TOP_RIGHT ||\n this.anchor == $.ControlAnchor.BOTTOM_RIGHT ) {\n this.container.insertBefore(\n this.wrapper,\n this.container.firstChild\n );\n } else {\n this.container.appendChild( this.wrapper );\n }\n } else {\n parent.appendChild( this.wrapper );\n }\n};\n\n/** @lends OpenSeadragon.Control.prototype */\n$.Control.prototype = {\n\n /**\n * Removes the control from the container.\n * @function\n */\n destroy: function() {\n this.wrapper.removeChild( this.element );\n this.container.removeChild( this.wrapper );\n },\n\n /**\n * Determines if the control is currently visible.\n * @function\n * @return {Boolean} true if currenly visible, false otherwise.\n */\n isVisible: function() {\n return this.wrapper.style.display != \"none\";\n },\n\n /**\n * Toggles the visibility of the control.\n * @function\n * @param {Boolean} visible - true to make visible, false to hide.\n */\n setVisible: function( visible ) {\n this.wrapper.style.display = visible ?\n ( this.anchor == $.ControlAnchor.ABSOLUTE ? 'block' : 'inline-block' ) :\n \"none\";\n },\n\n /**\n * Sets the opacity level for the control.\n * @function\n * @param {Number} opactiy - a value between 1 and 0 inclusively.\n */\n setOpacity: function( opacity ) {\n if ( this.element[ $.SIGNAL ] && $.Browser.vendor == $.BROWSERS.IE ) {\n $.setElementOpacity( this.element, opacity, true );\n } else {\n $.setElementOpacity( this.wrapper, opacity, true );\n }\n }\n};\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - ControlDock\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n /**\n * @class ControlDock\n * @classdesc Provides a container element (a <form> element) with support for the layout of control elements.\n *\n * @memberof OpenSeadragon\n */\n $.ControlDock = function( options ){\n var layouts = [ 'topleft', 'topright', 'bottomright', 'bottomleft'],\n layout,\n i;\n\n $.extend( true, this, {\n id: 'controldock-' + $.now() + '-' + Math.floor(Math.random() * 1000000),\n container: $.makeNeutralElement( 'div' ),\n controls: []\n }, options );\n\n // Disable the form's submit; otherwise button clicks and return keys\n // can trigger it.\n this.container.onsubmit = function() {\n return false;\n };\n\n if( this.element ){\n this.element = $.getElement( this.element );\n this.element.appendChild( this.container );\n this.element.style.position = 'relative';\n this.container.style.width = '100%';\n this.container.style.height = '100%';\n }\n\n for( i = 0; i < layouts.length; i++ ){\n layout = layouts[ i ];\n this.controls[ layout ] = $.makeNeutralElement( \"div\" );\n this.controls[ layout ].style.position = 'absolute';\n if ( layout.match( 'left' ) ){\n this.controls[ layout ].style.left = '0px';\n }\n if ( layout.match( 'right' ) ){\n this.controls[ layout ].style.right = '0px';\n }\n if ( layout.match( 'top' ) ){\n this.controls[ layout ].style.top = '0px';\n }\n if ( layout.match( 'bottom' ) ){\n this.controls[ layout ].style.bottom = '0px';\n }\n }\n\n this.container.appendChild( this.controls.topleft );\n this.container.appendChild( this.controls.topright );\n this.container.appendChild( this.controls.bottomright );\n this.container.appendChild( this.controls.bottomleft );\n };\n\n /** @lends OpenSeadragon.ControlDock.prototype */\n $.ControlDock.prototype = {\n\n /**\n * @function\n */\n addControl: function ( element, controlOptions ) {\n element = $.getElement( element );\n var div = null;\n\n if ( getControlIndex( this, element ) >= 0 ) {\n return; // they're trying to add a duplicate control\n }\n\n switch ( controlOptions.anchor ) {\n case $.ControlAnchor.TOP_RIGHT:\n div = this.controls.topright;\n element.style.position = \"relative\";\n element.style.paddingRight = \"0px\";\n element.style.paddingTop = \"0px\";\n break;\n case $.ControlAnchor.BOTTOM_RIGHT:\n div = this.controls.bottomright;\n element.style.position = \"relative\";\n element.style.paddingRight = \"0px\";\n element.style.paddingBottom = \"0px\";\n break;\n case $.ControlAnchor.BOTTOM_LEFT:\n div = this.controls.bottomleft;\n element.style.position = \"relative\";\n element.style.paddingLeft = \"0px\";\n element.style.paddingBottom = \"0px\";\n break;\n case $.ControlAnchor.TOP_LEFT:\n div = this.controls.topleft;\n element.style.position = \"relative\";\n element.style.paddingLeft = \"0px\";\n element.style.paddingTop = \"0px\";\n break;\n case $.ControlAnchor.ABSOLUTE:\n div = this.container;\n element.style.margin = \"0px\";\n element.style.padding = \"0px\";\n break;\n default:\n case $.ControlAnchor.NONE:\n div = this.container;\n element.style.margin = \"0px\";\n element.style.padding = \"0px\";\n break;\n }\n\n this.controls.push(\n new $.Control( element, controlOptions, div )\n );\n element.style.display = \"inline-block\";\n },\n\n\n /**\n * @function\n * @return {OpenSeadragon.ControlDock} Chainable.\n */\n removeControl: function ( element ) {\n element = $.getElement( element );\n var i = getControlIndex( this, element );\n\n if ( i >= 0 ) {\n this.controls[ i ].destroy();\n this.controls.splice( i, 1 );\n }\n\n return this;\n },\n\n /**\n * @function\n * @return {OpenSeadragon.ControlDock} Chainable.\n */\n clearControls: function () {\n while ( this.controls.length > 0 ) {\n this.controls.pop().destroy();\n }\n\n return this;\n },\n\n\n /**\n * @function\n * @return {Boolean}\n */\n areControlsEnabled: function () {\n var i;\n\n for ( i = this.controls.length - 1; i >= 0; i-- ) {\n if ( this.controls[ i ].isVisible() ) {\n return true;\n }\n }\n\n return false;\n },\n\n\n /**\n * @function\n * @return {OpenSeadragon.ControlDock} Chainable.\n */\n setControlsEnabled: function( enabled ) {\n var i;\n\n for ( i = this.controls.length - 1; i >= 0; i-- ) {\n this.controls[ i ].setVisible( enabled );\n }\n\n return this;\n }\n\n };\n\n\n ///////////////////////////////////////////////////////////////////////////////\n // Utility methods\n ///////////////////////////////////////////////////////////////////////////////\n function getControlIndex( dock, element ) {\n var controls = dock.controls,\n i;\n\n for ( i = controls.length - 1; i >= 0; i-- ) {\n if ( controls[ i ].element == element ) {\n return i;\n }\n }\n\n return -1;\n }\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - Placement\n *\n * Copyright (C) 2010-2016 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function($) {\n\n /**\n * An enumeration of positions to anchor an element.\n * @member Placement\n * @memberOf OpenSeadragon\n * @static\n * @readonly\n * @property {OpenSeadragon.Placement} CENTER\n * @property {OpenSeadragon.Placement} TOP_LEFT\n * @property {OpenSeadragon.Placement} TOP\n * @property {OpenSeadragon.Placement} TOP_RIGHT\n * @property {OpenSeadragon.Placement} RIGHT\n * @property {OpenSeadragon.Placement} BOTTOM_RIGHT\n * @property {OpenSeadragon.Placement} BOTTOM\n * @property {OpenSeadragon.Placement} BOTTOM_LEFT\n * @property {OpenSeadragon.Placement} LEFT\n */\n $.Placement = $.freezeObject({\n CENTER: 0,\n TOP_LEFT: 1,\n TOP: 2,\n TOP_RIGHT: 3,\n RIGHT: 4,\n BOTTOM_RIGHT: 5,\n BOTTOM: 6,\n BOTTOM_LEFT: 7,\n LEFT: 8,\n properties: {\n 0: {\n isLeft: false,\n isHorizontallyCentered: true,\n isRight: false,\n isTop: false,\n isVerticallyCentered: true,\n isBottom: false\n },\n 1: {\n isLeft: true,\n isHorizontallyCentered: false,\n isRight: false,\n isTop: true,\n isVerticallyCentered: false,\n isBottom: false\n },\n 2: {\n isLeft: false,\n isHorizontallyCentered: true,\n isRight: false,\n isTop: true,\n isVerticallyCentered: false,\n isBottom: false\n },\n 3: {\n isLeft: false,\n isHorizontallyCentered: false,\n isRight: true,\n isTop: true,\n isVerticallyCentered: false,\n isBottom: false\n },\n 4: {\n isLeft: false,\n isHorizontallyCentered: false,\n isRight: true,\n isTop: false,\n isVerticallyCentered: true,\n isBottom: false\n },\n 5: {\n isLeft: false,\n isHorizontallyCentered: false,\n isRight: true,\n isTop: false,\n isVerticallyCentered: false,\n isBottom: true\n },\n 6: {\n isLeft: false,\n isHorizontallyCentered: true,\n isRight: false,\n isTop: false,\n isVerticallyCentered: false,\n isBottom: true\n },\n 7: {\n isLeft: true,\n isHorizontallyCentered: false,\n isRight: false,\n isTop: false,\n isVerticallyCentered: false,\n isBottom: true\n },\n 8: {\n isLeft: true,\n isHorizontallyCentered: false,\n isRight: false,\n isTop: false,\n isVerticallyCentered: true,\n isBottom: false\n }\n }\n });\n\n}(OpenSeadragon));\n","/*\n * OpenSeadragon - Viewer\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n// dictionary from hash to private properties\nvar THIS = {};\nvar nextHash = 1;\n\n/**\n *\n * The main point of entry into creating a zoomable image on the page.
      \n *
      \n * We have provided an idiomatic javascript constructor which takes\n * a single object, but still support the legacy positional arguments.
      \n *
      \n * The options below are given in order that they appeared in the constructor\n * as arguments and we translate a positional call into an idiomatic call.
      \n *
      \n * To create a viewer, you can use either of this methods:
      \n *
        \n *
      • var viewer = new OpenSeadragon.Viewer(options);
      • \n *
      • var viewer = OpenSeadragon(options);
      • \n *
      \n * @class Viewer\n * @classdesc The main OpenSeadragon viewer class.\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.EventSource\n * @extends OpenSeadragon.ControlDock\n * @param {OpenSeadragon.Options} options - Viewer options.\n *\n **/\n$.Viewer = function( options ) {\n\n var args = arguments,\n _this = this,\n i;\n\n\n //backward compatibility for positional args while prefering more\n //idiomatic javascript options object as the only argument\n if( !$.isPlainObject( options ) ){\n options = {\n id: args[ 0 ],\n xmlPath: args.length > 1 ? args[ 1 ] : undefined,\n prefixUrl: args.length > 2 ? args[ 2 ] : undefined,\n controls: args.length > 3 ? args[ 3 ] : undefined,\n overlays: args.length > 4 ? args[ 4 ] : undefined\n };\n }\n\n //options.config and the general config argument are deprecated\n //in favor of the more direct specification of optional settings\n //being pass directly on the options object\n if ( options.config ){\n $.extend( true, options, options.config );\n delete options.config;\n }\n\n //Public properties\n //Allow the options object to override global defaults\n $.extend( true, this, {\n\n //internal state and dom identifiers\n id: options.id,\n hash: options.hash || nextHash++,\n /**\n * Index for page to be shown first next time open() is called (only used in sequenceMode).\n * @member {Number} initialPage\n * @memberof OpenSeadragon.Viewer#\n */\n initialPage: 0,\n\n //dom nodes\n /**\n * The parent element of this Viewer instance, passed in when the Viewer was created.\n * @member {Element} element\n * @memberof OpenSeadragon.Viewer#\n */\n element: null,\n /**\n * A <div> element (provided by {@link OpenSeadragon.ControlDock}), the base element of this Viewer instance.

      \n * Child element of {@link OpenSeadragon.Viewer#element}.\n * @member {Element} container\n * @memberof OpenSeadragon.Viewer#\n */\n container: null,\n /**\n * A <div> element, the element where user-input events are handled for panning and zooming.

      \n * Child element of {@link OpenSeadragon.Viewer#container},\n * positioned on top of {@link OpenSeadragon.Viewer#keyboardCommandArea}.

      \n * The parent of {@link OpenSeadragon.Drawer#canvas} instances.\n * @member {Element} canvas\n * @memberof OpenSeadragon.Viewer#\n */\n canvas: null,\n\n // Overlays list. An overlay allows to add html on top of the viewer.\n overlays: [],\n // Container inside the canvas where overlays are drawn.\n overlaysContainer: null,\n\n //private state properties\n previousBody: [],\n\n //This was originally initialized in the constructor and so could never\n //have anything in it. now it can because we allow it to be specified\n //in the options and is only empty by default if not specified. Also\n //this array was returned from get_controls which I find confusing\n //since this object has a controls property which is treated in other\n //functions like clearControls. I'm removing the accessors.\n customControls: [],\n\n //These are originally not part options but declared as members\n //in initialize. It's still considered idiomatic to put them here\n source: null,\n /**\n * Handles rendering of tiles in the viewer. Created for each TileSource opened.\n * @member {OpenSeadragon.Drawer} drawer\n * @memberof OpenSeadragon.Viewer#\n */\n drawer: null,\n world: null,\n /**\n * Handles coordinate-related functionality - zoom, pan, rotation, etc. Created for each TileSource opened.\n * @member {OpenSeadragon.Viewport} viewport\n * @memberof OpenSeadragon.Viewer#\n */\n viewport: null,\n /**\n * @member {OpenSeadragon.Navigator} navigator\n * @memberof OpenSeadragon.Viewer#\n */\n navigator: null,\n\n //A collection viewport is a separate viewport used to provide\n //simultaneous rendering of sets of tiles\n collectionViewport: null,\n collectionDrawer: null,\n\n //UI image resources\n //TODO: rename navImages to uiImages\n navImages: null,\n\n //interface button controls\n buttons: null,\n\n //TODO: this is defunct so safely remove it\n profiler: null\n\n }, $.DEFAULT_SETTINGS, options );\n\n if ( typeof( this.hash) === \"undefined\" ) {\n throw new Error(\"A hash must be defined, either by specifying options.id or options.hash.\");\n }\n if ( typeof( THIS[ this.hash ] ) !== \"undefined\" ) {\n // We don't want to throw an error here, as the user might have discarded\n // the previous viewer with the same hash and now want to recreate it.\n $.console.warn(\"Hash \" + this.hash + \" has already been used.\");\n }\n\n //Private state properties\n THIS[ this.hash ] = {\n \"fsBoundsDelta\": new $.Point( 1, 1 ),\n \"prevContainerSize\": null,\n \"animating\": false,\n \"forceRedraw\": false,\n \"mouseInside\": false,\n \"group\": null,\n // whether we should be continuously zooming\n \"zooming\": false,\n // how much we should be continuously zooming by\n \"zoomFactor\": null,\n \"lastZoomTime\": null,\n \"fullPage\": false,\n \"onfullscreenchange\": null\n };\n\n this._sequenceIndex = 0;\n this._firstOpen = true;\n this._updateRequestId = null;\n this._loadQueue = [];\n this.currentOverlays = [];\n\n this._lastScrollTime = $.now(); // variable used to help normalize the scroll event speed of different devices\n\n //Inherit some behaviors and properties\n $.EventSource.call( this );\n\n this.addHandler( 'open-failed', function ( event ) {\n var msg = $.getString( \"Errors.OpenFailed\", event.eventSource, event.message);\n _this._showMessage( msg );\n });\n\n $.ControlDock.call( this, options );\n\n //Deal with tile sources\n if (this.xmlPath) {\n //Deprecated option. Now it is preferred to use the tileSources option\n this.tileSources = [ this.xmlPath ];\n }\n\n this.element = this.element || document.getElementById( this.id );\n this.canvas = $.makeNeutralElement( \"div\" );\n\n this.canvas.className = \"openseadragon-canvas\";\n (function( style ){\n style.width = \"100%\";\n style.height = \"100%\";\n style.overflow = \"hidden\";\n style.position = \"absolute\";\n style.top = \"0px\";\n style.left = \"0px\";\n }(this.canvas.style));\n $.setElementTouchActionNone( this.canvas );\n if (options.tabIndex !== \"\") {\n this.canvas.tabIndex = (options.tabIndex === undefined ? 0 : options.tabIndex);\n }\n\n //the container is created through applying the ControlDock constructor above\n this.container.className = \"openseadragon-container\";\n (function( style ){\n style.width = \"100%\";\n style.height = \"100%\";\n style.position = \"relative\";\n style.overflow = \"hidden\";\n style.left = \"0px\";\n style.top = \"0px\";\n style.textAlign = \"left\"; // needed to protect against\n }( this.container.style ));\n\n this.container.insertBefore( this.canvas, this.container.firstChild );\n this.element.appendChild( this.container );\n\n //Used for toggling between fullscreen and default container size\n //TODO: these can be closure private and shared across Viewer\n // instances.\n this.bodyWidth = document.body.style.width;\n this.bodyHeight = document.body.style.height;\n this.bodyOverflow = document.body.style.overflow;\n this.docOverflow = document.documentElement.style.overflow;\n\n this.innerTracker = new $.MouseTracker({\n element: this.canvas,\n startDisabled: !this.mouseNavEnabled,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n dblClickTimeThreshold: this.dblClickTimeThreshold,\n dblClickDistThreshold: this.dblClickDistThreshold,\n keyDownHandler: $.delegate( this, onCanvasKeyDown ),\n keyHandler: $.delegate( this, onCanvasKeyPress ),\n clickHandler: $.delegate( this, onCanvasClick ),\n dblClickHandler: $.delegate( this, onCanvasDblClick ),\n dragHandler: $.delegate( this, onCanvasDrag ),\n dragEndHandler: $.delegate( this, onCanvasDragEnd ),\n enterHandler: $.delegate( this, onCanvasEnter ),\n exitHandler: $.delegate( this, onCanvasExit ),\n pressHandler: $.delegate( this, onCanvasPress ),\n releaseHandler: $.delegate( this, onCanvasRelease ),\n nonPrimaryPressHandler: $.delegate( this, onCanvasNonPrimaryPress ),\n nonPrimaryReleaseHandler: $.delegate( this, onCanvasNonPrimaryRelease ),\n scrollHandler: $.delegate( this, onCanvasScroll ),\n pinchHandler: $.delegate( this, onCanvasPinch )\n });\n\n this.outerTracker = new $.MouseTracker({\n element: this.container,\n startDisabled: !this.mouseNavEnabled,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n dblClickTimeThreshold: this.dblClickTimeThreshold,\n dblClickDistThreshold: this.dblClickDistThreshold,\n enterHandler: $.delegate( this, onContainerEnter ),\n exitHandler: $.delegate( this, onContainerExit )\n });\n\n if( this.toolbar ){\n this.toolbar = new $.ControlDock({ element: this.toolbar });\n }\n\n this.bindStandardControls();\n\n THIS[ this.hash ].prevContainerSize = _getSafeElemSize( this.container );\n\n // Create the world\n this.world = new $.World({\n viewer: this\n });\n\n this.world.addHandler('add-item', function(event) {\n // For backwards compatibility, we maintain the source property\n _this.source = _this.world.getItemAt(0).source;\n\n THIS[ _this.hash ].forceRedraw = true;\n\n if (!_this._updateRequestId) {\n _this._updateRequestId = scheduleUpdate( _this, updateMulti );\n }\n });\n\n this.world.addHandler('remove-item', function(event) {\n // For backwards compatibility, we maintain the source property\n if (_this.world.getItemCount()) {\n _this.source = _this.world.getItemAt(0).source;\n } else {\n _this.source = null;\n }\n\n THIS[ _this.hash ].forceRedraw = true;\n });\n\n this.world.addHandler('metrics-change', function(event) {\n if (_this.viewport) {\n _this.viewport._setContentBounds(_this.world.getHomeBounds(), _this.world.getContentFactor());\n }\n });\n\n this.world.addHandler('item-index-change', function(event) {\n // For backwards compatibility, we maintain the source property\n _this.source = _this.world.getItemAt(0).source;\n });\n\n // Create the viewport\n this.viewport = new $.Viewport({\n containerSize: THIS[ this.hash ].prevContainerSize,\n springStiffness: this.springStiffness,\n animationTime: this.animationTime,\n minZoomImageRatio: this.minZoomImageRatio,\n maxZoomPixelRatio: this.maxZoomPixelRatio,\n visibilityRatio: this.visibilityRatio,\n wrapHorizontal: this.wrapHorizontal,\n wrapVertical: this.wrapVertical,\n defaultZoomLevel: this.defaultZoomLevel,\n minZoomLevel: this.minZoomLevel,\n maxZoomLevel: this.maxZoomLevel,\n viewer: this,\n degrees: this.degrees,\n navigatorRotate: this.navigatorRotate,\n homeFillsViewer: this.homeFillsViewer,\n margins: this.viewportMargins\n });\n\n this.viewport._setContentBounds(this.world.getHomeBounds(), this.world.getContentFactor());\n\n // Create the image loader\n this.imageLoader = new $.ImageLoader({\n jobLimit: this.imageLoaderLimit,\n timeout: options.timeout\n });\n\n // Create the tile cache\n this.tileCache = new $.TileCache({\n maxImageCacheCount: this.maxImageCacheCount\n });\n\n // Create the drawer\n this.drawer = new $.Drawer({\n viewer: this,\n viewport: this.viewport,\n element: this.canvas,\n debugGridColor: this.debugGridColor\n });\n\n // Overlay container\n this.overlaysContainer = $.makeNeutralElement( \"div\" );\n this.canvas.appendChild( this.overlaysContainer );\n\n // Now that we have a drawer, see if it supports rotate. If not we need to remove the rotate buttons\n if (!this.drawer.canRotate()) {\n // Disable/remove the rotate left/right buttons since they aren't supported\n if (this.rotateLeft) {\n i = this.buttons.buttons.indexOf(this.rotateLeft);\n this.buttons.buttons.splice(i, 1);\n this.buttons.element.removeChild(this.rotateLeft.element);\n }\n if (this.rotateRight) {\n i = this.buttons.buttons.indexOf(this.rotateRight);\n this.buttons.buttons.splice(i, 1);\n this.buttons.element.removeChild(this.rotateRight.element);\n }\n }\n\n //Instantiate a navigator if configured\n if ( this.showNavigator){\n this.navigator = new $.Navigator({\n id: this.navigatorId,\n position: this.navigatorPosition,\n sizeRatio: this.navigatorSizeRatio,\n maintainSizeRatio: this.navigatorMaintainSizeRatio,\n top: this.navigatorTop,\n left: this.navigatorLeft,\n width: this.navigatorWidth,\n height: this.navigatorHeight,\n autoResize: this.navigatorAutoResize,\n autoFade: this.navigatorAutoFade,\n prefixUrl: this.prefixUrl,\n viewer: this,\n navigatorRotate: this.navigatorRotate,\n crossOriginPolicy: this.crossOriginPolicy\n });\n }\n\n // Sequence mode\n if (this.sequenceMode) {\n this.bindSequenceControls();\n }\n\n // Open initial tilesources\n if (this.tileSources) {\n this.open( this.tileSources );\n }\n\n // Add custom controls\n for ( i = 0; i < this.customControls.length; i++ ) {\n this.addControl(\n this.customControls[ i ].id,\n {anchor: this.customControls[ i ].anchor}\n );\n }\n\n // Initial fade out\n $.requestAnimationFrame( function(){\n beginControlsAutoHide( _this );\n } );\n};\n\n$.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, /** @lends OpenSeadragon.Viewer.prototype */{\n\n\n /**\n * @function\n * @return {Boolean}\n */\n isOpen: function () {\n return !!this.world.getItemCount();\n },\n\n // deprecated\n openDzi: function ( dzi ) {\n $.console.error( \"[Viewer.openDzi] this function is deprecated; use Viewer.open() instead.\" );\n return this.open( dzi );\n },\n\n // deprecated\n openTileSource: function ( tileSource ) {\n $.console.error( \"[Viewer.openTileSource] this function is deprecated; use Viewer.open() instead.\" );\n return this.open( tileSource );\n },\n\n /**\n * Open tiled images into the viewer, closing any others.\n * @function\n * @param {Array|String|Object|Function} tileSources - This can be a TiledImage\n * specifier, a TileSource specifier, or an array of either. A TiledImage specifier\n * is the same as the options parameter for {@link OpenSeadragon.Viewer#addTiledImage},\n * except for the index property; images are added in sequence.\n * A TileSource specifier is anything you could pass as the tileSource property\n * of the options parameter for {@link OpenSeadragon.Viewer#addTiledImage}.\n * @param {Number} initialPage - If sequenceMode is true, display this page initially\n * for the given tileSources. If specified, will overwrite the Viewer's existing initialPage property.\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:open\n * @fires OpenSeadragon.Viewer.event:open-failed\n */\n open: function (tileSources, initialPage) {\n var _this = this;\n\n this.close();\n\n if (!tileSources) {\n return;\n }\n\n if (this.sequenceMode && $.isArray(tileSources)) {\n if (this.referenceStrip) {\n this.referenceStrip.destroy();\n this.referenceStrip = null;\n }\n\n if (typeof initialPage != 'undefined' && !isNaN(initialPage)) {\n this.initialPage = initialPage;\n }\n\n this.tileSources = tileSources;\n this._sequenceIndex = Math.max(0, Math.min(this.tileSources.length - 1, this.initialPage));\n if (this.tileSources.length) {\n this.open(this.tileSources[this._sequenceIndex]);\n\n if ( this.showReferenceStrip ){\n this.addReferenceStrip();\n }\n }\n\n this._updateSequenceButtons( this._sequenceIndex );\n return;\n }\n\n if (!$.isArray(tileSources)) {\n tileSources = [tileSources];\n }\n\n if (!tileSources.length) {\n return;\n }\n\n this._opening = true;\n\n var expected = tileSources.length;\n var successes = 0;\n var failures = 0;\n var failEvent;\n\n var checkCompletion = function() {\n if (successes + failures === expected) {\n if (successes) {\n if (_this._firstOpen || !_this.preserveViewport) {\n _this.viewport.goHome( true );\n _this.viewport.update();\n }\n\n _this._firstOpen = false;\n\n var source = tileSources[0];\n if (source.tileSource) {\n source = source.tileSource;\n }\n\n // Global overlays\n if( _this.overlays && !_this.preserveOverlays ){\n for ( var i = 0; i < _this.overlays.length; i++ ) {\n _this.currentOverlays[ i ] = getOverlayObject( _this, _this.overlays[ i ] );\n }\n }\n\n _this._drawOverlays();\n _this._opening = false;\n\n /**\n * Raised when the viewer has opened and loaded one or more TileSources.\n *\n * @event open\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {OpenSeadragon.TileSource} source - The tile source that was opened.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n // TODO: what if there are multiple sources?\n _this.raiseEvent( 'open', { source: source } );\n } else {\n _this._opening = false;\n\n /**\n * Raised when an error occurs loading a TileSource.\n *\n * @event open-failed\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {String} message - Information about what failed.\n * @property {String} source - The tile source that failed.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( 'open-failed', failEvent );\n }\n }\n };\n\n var doOne = function(options) {\n if (!$.isPlainObject(options) || !options.tileSource) {\n options = {\n tileSource: options\n };\n }\n\n if (options.index !== undefined) {\n $.console.error('[Viewer.open] setting indexes here is not supported; use addTiledImage instead');\n delete options.index;\n }\n\n if (options.collectionImmediately === undefined) {\n options.collectionImmediately = true;\n }\n\n var originalSuccess = options.success;\n options.success = function(event) {\n successes++;\n\n // TODO: now that options has other things besides tileSource, the overlays\n // should probably be at the options level, not the tileSource level.\n if (options.tileSource.overlays) {\n for (var i = 0; i < options.tileSource.overlays.length; i++) {\n _this.addOverlay(options.tileSource.overlays[i]);\n }\n }\n\n if (originalSuccess) {\n originalSuccess(event);\n }\n\n checkCompletion();\n };\n\n var originalError = options.error;\n options.error = function(event) {\n failures++;\n\n if (!failEvent) {\n failEvent = event;\n }\n\n if (originalError) {\n originalError(event);\n }\n\n checkCompletion();\n };\n\n _this.addTiledImage(options);\n };\n\n // TileSources\n for (var i = 0; i < tileSources.length; i++) {\n doOne(tileSources[i]);\n }\n\n return this;\n },\n\n\n /**\n * @function\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:close\n */\n close: function ( ) {\n if ( !THIS[ this.hash ] ) {\n //this viewer has already been destroyed: returning immediately\n return this;\n }\n\n this._opening = false;\n\n if ( this.navigator ) {\n this.navigator.close();\n }\n\n if (!this.preserveOverlays) {\n this.clearOverlays();\n this.overlaysContainer.innerHTML = \"\";\n }\n\n THIS[ this.hash ].animating = false;\n this.world.removeAll();\n this.imageLoader.clear();\n\n /**\n * Raised when the viewer is closed (see {@link OpenSeadragon.Viewer#close}).\n *\n * @event close\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'close' );\n\n return this;\n },\n\n\n /**\n * Function to destroy the viewer and clean up everything created by OpenSeadragon.\n *\n * Example:\n * var viewer = OpenSeadragon({\n * [...]\n * });\n *\n * //when you are done with the viewer:\n * viewer.destroy();\n * viewer = null; //important\n *\n * @function\n */\n destroy: function( ) {\n if ( !THIS[ this.hash ] ) {\n //this viewer has already been destroyed: returning immediately\n return;\n }\n\n this.close();\n\n this.clearOverlays();\n this.overlaysContainer.innerHTML = \"\";\n\n //TODO: implement this...\n //this.unbindSequenceControls()\n //this.unbindStandardControls()\n\n if (this.referenceStrip) {\n this.referenceStrip.destroy();\n this.referenceStrip = null;\n }\n\n if ( this._updateRequestId !== null ) {\n $.cancelAnimationFrame( this._updateRequestId );\n this._updateRequestId = null;\n }\n\n if ( this.drawer ) {\n this.drawer.destroy();\n }\n\n this.removeAllHandlers();\n\n // Go through top element (passed to us) and remove all children\n // Use removeChild to make sure it handles SVG or any non-html\n // also it performs better - http://jsperf.com/innerhtml-vs-removechild/15\n if (this.element){\n while (this.element.firstChild) {\n this.element.removeChild(this.element.firstChild);\n }\n }\n\n // destroy the mouse trackers\n if (this.innerTracker){\n this.innerTracker.destroy();\n }\n if (this.outerTracker){\n this.outerTracker.destroy();\n }\n\n THIS[ this.hash ] = null;\n delete THIS[ this.hash ];\n\n // clear all our references to dom objects\n this.canvas = null;\n this.container = null;\n\n // clear our reference to the main element - they will need to pass it in again, creating a new viewer\n this.element = null;\n },\n\n /**\n * @function\n * @return {Boolean}\n */\n isMouseNavEnabled: function () {\n return this.innerTracker.isTracking();\n },\n\n /**\n * @function\n * @param {Boolean} enabled - true to enable, false to disable\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:mouse-enabled\n */\n setMouseNavEnabled: function( enabled ){\n this.innerTracker.setTracking( enabled );\n this.outerTracker.setTracking( enabled );\n /**\n * Raised when mouse/touch navigation is enabled or disabled (see {@link OpenSeadragon.Viewer#setMouseNavEnabled}).\n *\n * @event mouse-enabled\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Boolean} enabled\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'mouse-enabled', { enabled: enabled } );\n return this;\n },\n\n\n /**\n * @function\n * @return {Boolean}\n */\n areControlsEnabled: function () {\n var enabled = this.controls.length,\n i;\n for( i = 0; i < this.controls.length; i++ ){\n enabled = enabled && this.controls[ i ].isVisibile();\n }\n return enabled;\n },\n\n\n /**\n * Shows or hides the controls (e.g. the default navigation buttons).\n *\n * @function\n * @param {Boolean} true to show, false to hide.\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:controls-enabled\n */\n setControlsEnabled: function( enabled ) {\n if( enabled ){\n abortControlsAutoHide( this );\n } else {\n beginControlsAutoHide( this );\n }\n /**\n * Raised when the navigation controls are shown or hidden (see {@link OpenSeadragon.Viewer#setControlsEnabled}).\n *\n * @event controls-enabled\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Boolean} enabled\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'controls-enabled', { enabled: enabled } );\n return this;\n },\n\n /**\n * Turns debugging mode on or off for this viewer.\n *\n * @function\n * @param {Boolean} true to turn debug on, false to turn debug off.\n */\n setDebugMode: function(debugMode){\n\n for (var i = 0; i < this.world.getItemCount(); i++) {\n this.world.getItemAt(i).debugMode = debugMode;\n }\n\n this.debugMode = debugMode;\n this.forceRedraw();\n },\n\n /**\n * @function\n * @return {Boolean}\n */\n isFullPage: function () {\n return THIS[ this.hash ].fullPage;\n },\n\n\n /**\n * Toggle full page mode.\n * @function\n * @param {Boolean} fullPage\n * If true, enter full page mode. If false, exit full page mode.\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:pre-full-page\n * @fires OpenSeadragon.Viewer.event:full-page\n */\n setFullPage: function( fullPage ) {\n\n var body = document.body,\n bodyStyle = body.style,\n docStyle = document.documentElement.style,\n _this = this,\n nodes,\n i;\n\n //dont bother modifying the DOM if we are already in full page mode.\n if ( fullPage == this.isFullPage() ) {\n return this;\n }\n\n var fullPageEventArgs = {\n fullPage: fullPage,\n preventDefaultAction: false\n };\n /**\n * Raised when the viewer is about to change to/from full-page mode (see {@link OpenSeadragon.Viewer#setFullPage}).\n *\n * @event pre-full-page\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Boolean} fullPage - True if entering full-page mode, false if exiting full-page mode.\n * @property {Boolean} preventDefaultAction - Set to true to prevent full-page mode change. Default: false.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'pre-full-page', fullPageEventArgs );\n if ( fullPageEventArgs.preventDefaultAction ) {\n return this;\n }\n\n if ( fullPage ) {\n\n this.elementSize = $.getElementSize( this.element );\n this.pageScroll = $.getPageScroll();\n\n this.elementMargin = this.element.style.margin;\n this.element.style.margin = \"0\";\n this.elementPadding = this.element.style.padding;\n this.element.style.padding = \"0\";\n\n this.bodyMargin = bodyStyle.margin;\n this.docMargin = docStyle.margin;\n bodyStyle.margin = \"0\";\n docStyle.margin = \"0\";\n\n this.bodyPadding = bodyStyle.padding;\n this.docPadding = docStyle.padding;\n bodyStyle.padding = \"0\";\n docStyle.padding = \"0\";\n\n this.bodyWidth = bodyStyle.width;\n this.docWidth = docStyle.width;\n bodyStyle.width = \"100%\";\n docStyle.width = \"100%\";\n\n this.bodyHeight = bodyStyle.height;\n this.docHeight = docStyle.height;\n bodyStyle.height = \"100%\";\n docStyle.height = \"100%\";\n\n //when entering full screen on the ipad it wasnt sufficient to leave\n //the body intact as only only the top half of the screen would\n //respond to touch events on the canvas, while the bottom half treated\n //them as touch events on the document body. Thus we remove and store\n //the bodies elements and replace them when we leave full screen.\n this.previousBody = [];\n THIS[ this.hash ].prevElementParent = this.element.parentNode;\n THIS[ this.hash ].prevNextSibling = this.element.nextSibling;\n THIS[ this.hash ].prevElementWidth = this.element.style.width;\n THIS[ this.hash ].prevElementHeight = this.element.style.height;\n nodes = body.childNodes.length;\n for ( i = 0; i < nodes; i++ ) {\n this.previousBody.push( body.childNodes[ 0 ] );\n body.removeChild( body.childNodes[ 0 ] );\n }\n\n //If we've got a toolbar, we need to enable the user to use css to\n //preserve it in fullpage mode\n if ( this.toolbar && this.toolbar.element ) {\n //save a reference to the parent so we can put it back\n //in the long run we need a better strategy\n this.toolbar.parentNode = this.toolbar.element.parentNode;\n this.toolbar.nextSibling = this.toolbar.element.nextSibling;\n body.appendChild( this.toolbar.element );\n\n //Make sure the user has some ability to style the toolbar based\n //on the mode\n $.addClass( this.toolbar.element, 'fullpage' );\n }\n\n $.addClass( this.element, 'fullpage' );\n body.appendChild( this.element );\n\n this.element.style.height = $.getWindowSize().y + 'px';\n this.element.style.width = $.getWindowSize().x + 'px';\n\n if ( this.toolbar && this.toolbar.element ) {\n this.element.style.height = (\n $.getElementSize( this.element ).y - $.getElementSize( this.toolbar.element ).y\n ) + 'px';\n }\n\n THIS[ this.hash ].fullPage = true;\n\n // mouse will be inside container now\n $.delegate( this, onContainerEnter )( {} );\n\n } else {\n\n this.element.style.margin = this.elementMargin;\n this.element.style.padding = this.elementPadding;\n\n bodyStyle.margin = this.bodyMargin;\n docStyle.margin = this.docMargin;\n\n bodyStyle.padding = this.bodyPadding;\n docStyle.padding = this.docPadding;\n\n bodyStyle.width = this.bodyWidth;\n docStyle.width = this.docWidth;\n\n bodyStyle.height = this.bodyHeight;\n docStyle.height = this.docHeight;\n\n body.removeChild( this.element );\n nodes = this.previousBody.length;\n for ( i = 0; i < nodes; i++ ) {\n body.appendChild( this.previousBody.shift() );\n }\n\n $.removeClass( this.element, 'fullpage' );\n THIS[ this.hash ].prevElementParent.insertBefore(\n this.element,\n THIS[ this.hash ].prevNextSibling\n );\n\n //If we've got a toolbar, we need to enable the user to use css to\n //reset it to its original state\n if ( this.toolbar && this.toolbar.element ) {\n body.removeChild( this.toolbar.element );\n\n //Make sure the user has some ability to style the toolbar based\n //on the mode\n $.removeClass( this.toolbar.element, 'fullpage' );\n\n this.toolbar.parentNode.insertBefore(\n this.toolbar.element,\n this.toolbar.nextSibling\n );\n delete this.toolbar.parentNode;\n delete this.toolbar.nextSibling;\n }\n\n this.element.style.width = THIS[ this.hash ].prevElementWidth;\n this.element.style.height = THIS[ this.hash ].prevElementHeight;\n\n // After exiting fullPage or fullScreen, it can take some time\n // before the browser can actually set the scroll.\n var restoreScrollCounter = 0;\n var restoreScroll = function() {\n $.setPageScroll( _this.pageScroll );\n var pageScroll = $.getPageScroll();\n restoreScrollCounter++;\n if (restoreScrollCounter < 10 &&\n (pageScroll.x !== _this.pageScroll.x ||\n pageScroll.y !== _this.pageScroll.y)) {\n $.requestAnimationFrame( restoreScroll );\n }\n };\n $.requestAnimationFrame( restoreScroll );\n\n THIS[ this.hash ].fullPage = false;\n\n // mouse will likely be outside now\n $.delegate( this, onContainerExit )( { } );\n\n }\n\n if ( this.navigator && this.viewport ) {\n this.navigator.update( this.viewport );\n }\n\n /**\n * Raised when the viewer has changed to/from full-page mode (see {@link OpenSeadragon.Viewer#setFullPage}).\n *\n * @event full-page\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Boolean} fullPage - True if changed to full-page mode, false if exited full-page mode.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'full-page', { fullPage: fullPage } );\n\n return this;\n },\n\n /**\n * Toggle full screen mode if supported. Toggle full page mode otherwise.\n * @function\n * @param {Boolean} fullScreen\n * If true, enter full screen mode. If false, exit full screen mode.\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:pre-full-screen\n * @fires OpenSeadragon.Viewer.event:full-screen\n */\n setFullScreen: function( fullScreen ) {\n var _this = this;\n\n if ( !$.supportsFullScreen ) {\n return this.setFullPage( fullScreen );\n }\n\n if ( $.isFullScreen() === fullScreen ) {\n return this;\n }\n\n var fullScreeEventArgs = {\n fullScreen: fullScreen,\n preventDefaultAction: false\n };\n /**\n * Raised when the viewer is about to change to/from full-screen mode (see {@link OpenSeadragon.Viewer#setFullScreen}).\n * Note: the pre-full-screen event is not raised when the user is exiting\n * full-screen mode by pressing the Esc key. In that case, consider using\n * the full-screen, pre-full-page or full-page events.\n *\n * @event pre-full-screen\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Boolean} fullScreen - True if entering full-screen mode, false if exiting full-screen mode.\n * @property {Boolean} preventDefaultAction - Set to true to prevent full-screen mode change. Default: false.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'pre-full-screen', fullScreeEventArgs );\n if ( fullScreeEventArgs.preventDefaultAction ) {\n return this;\n }\n\n if ( fullScreen ) {\n\n this.setFullPage( true );\n // If the full page mode is not actually entered, we need to prevent\n // the full screen mode.\n if ( !this.isFullPage() ) {\n return this;\n }\n\n this.fullPageStyleWidth = this.element.style.width;\n this.fullPageStyleHeight = this.element.style.height;\n this.element.style.width = '100%';\n this.element.style.height = '100%';\n\n var onFullScreenChange = function() {\n var isFullScreen = $.isFullScreen();\n if ( !isFullScreen ) {\n $.removeEvent( document, $.fullScreenEventName, onFullScreenChange );\n $.removeEvent( document, $.fullScreenErrorEventName, onFullScreenChange );\n\n _this.setFullPage( false );\n if ( _this.isFullPage() ) {\n _this.element.style.width = _this.fullPageStyleWidth;\n _this.element.style.height = _this.fullPageStyleHeight;\n }\n }\n if ( _this.navigator && _this.viewport ) {\n _this.navigator.update( _this.viewport );\n }\n /**\n * Raised when the viewer has changed to/from full-screen mode (see {@link OpenSeadragon.Viewer#setFullScreen}).\n *\n * @event full-screen\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Boolean} fullScreen - True if changed to full-screen mode, false if exited full-screen mode.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( 'full-screen', { fullScreen: isFullScreen } );\n };\n $.addEvent( document, $.fullScreenEventName, onFullScreenChange );\n $.addEvent( document, $.fullScreenErrorEventName, onFullScreenChange );\n\n $.requestFullScreen( document.body );\n\n } else {\n $.exitFullScreen();\n }\n return this;\n },\n\n /**\n * @function\n * @return {Boolean}\n */\n isVisible: function () {\n return this.container.style.visibility != \"hidden\";\n },\n\n\n /**\n * @function\n * @param {Boolean} visible\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:visible\n */\n setVisible: function( visible ){\n this.container.style.visibility = visible ? \"\" : \"hidden\";\n /**\n * Raised when the viewer is shown or hidden (see {@link OpenSeadragon.Viewer#setVisible}).\n *\n * @event visible\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Boolean} visible\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'visible', { visible: visible } );\n return this;\n },\n\n /**\n * Add a tiled image to the viewer.\n * options.tileSource can be anything that {@link OpenSeadragon.Viewer#open}\n * supports except arrays of images.\n * Note that you can specify options.width or options.height, but not both.\n * The other dimension will be calculated according to the item's aspect ratio.\n * If collectionMode is on (see {@link OpenSeadragon.Options}), the new image is\n * automatically arranged with the others.\n * @function\n * @param {Object} options\n * @param {String|Object|Function} options.tileSource - The TileSource specifier.\n * A String implies a url used to determine the tileSource implementation\n * based on the file extension of url. JSONP is implied by *.js,\n * otherwise the url is retrieved as text and the resulting text is\n * introspected to determine if its json, xml, or text and parsed.\n * An Object implies an inline configuration which has a single\n * property sufficient for being able to determine tileSource\n * implementation. If the object has a property which is a function\n * named 'getTileUrl', it is treated as a custom TileSource.\n * @param {Number} [options.index] The index of the item. Added on top of\n * all other items if not specified.\n * @param {Boolean} [options.replace=false] If true, the item at options.index will be\n * removed and the new item is added in its place. options.tileSource will be\n * interpreted and fetched if necessary before the old item is removed to avoid leaving\n * a gap in the world.\n * @param {Number} [options.x=0] The X position for the image in viewport coordinates.\n * @param {Number} [options.y=0] The Y position for the image in viewport coordinates.\n * @param {Number} [options.width=1] The width for the image in viewport coordinates.\n * @param {Number} [options.height] The height for the image in viewport coordinates.\n * @param {OpenSeadragon.Rect} [options.fitBounds] The bounds in viewport coordinates\n * to fit the image into. If specified, x, y, width and height get ignored.\n * @param {OpenSeadragon.Placement} [options.fitBoundsPlacement=OpenSeadragon.Placement.CENTER]\n * How to anchor the image in the bounds if options.fitBounds is set.\n * @param {OpenSeadragon.Rect} [options.clip] - An area, in image pixels, to clip to\n * (portions of the image outside of this area will not be visible). Only works on\n * browsers that support the HTML5 canvas.\n * @param {Number} [options.opacity=1] Proportional opacity of the tiled images (1=opaque, 0=hidden)\n * @param {Boolean} [options.preload=false] Default switch for loading hidden images (true loads, false blocks)\n * @param {Number} [options.degrees=0] Initial rotation of the tiled image around\n * its top left corner in degrees.\n * @param {String} [options.compositeOperation] How the image is composited onto other images.\n * @param {String} [options.crossOriginPolicy] The crossOriginPolicy for this specific image,\n * overriding viewer.crossOriginPolicy.\n * @param {Boolean} [options.ajaxWithCredentials] Whether to set withCredentials on tile AJAX\n * @param {Boolean} [options.loadTilesWithAjax]\n * Whether to load tile data using AJAX requests.\n * Defaults to the setting in {@link OpenSeadragon.Options}.\n * @param {Object} [options.ajaxHeaders]\n * A set of headers to include when making tile AJAX requests.\n * Note that these headers will be merged over any headers specified in {@link OpenSeadragon.Options}.\n * Specifying a falsy value for a header will clear its existing value set at the Viewer level (if any).\n * requests.\n * @param {Function} [options.success] A function that gets called when the image is\n * successfully added. It's passed the event object which contains a single property:\n * \"item\", the resulting TiledImage.\n * @param {Function} [options.error] A function that gets called if the image is\n * unable to be added. It's passed the error event object, which contains \"message\"\n * and \"source\" properties.\n * @param {Boolean} [options.collectionImmediately=false] If collectionMode is on,\n * specifies whether to snap to the new arrangement immediately or to animate to it.\n * @param {String|CanvasGradient|CanvasPattern|Function} [options.placeholderFillStyle] - See {@link OpenSeadragon.Options}.\n * @fires OpenSeadragon.World.event:add-item\n * @fires OpenSeadragon.Viewer.event:add-item-failed\n */\n addTiledImage: function( options ) {\n $.console.assert(options, \"[Viewer.addTiledImage] options is required\");\n $.console.assert(options.tileSource, \"[Viewer.addTiledImage] options.tileSource is required\");\n $.console.assert(!options.replace || (options.index > -1 && options.index < this.world.getItemCount()),\n \"[Viewer.addTiledImage] if options.replace is used, options.index must be a valid index in Viewer.world\");\n\n var _this = this;\n\n if (options.replace) {\n options.replaceItem = _this.world.getItemAt(options.index);\n }\n\n this._hideMessage();\n\n if (options.placeholderFillStyle === undefined) {\n options.placeholderFillStyle = this.placeholderFillStyle;\n }\n if (options.opacity === undefined) {\n options.opacity = this.opacity;\n }\n if (options.preload === undefined) {\n options.preload = this.preload;\n }\n if (options.compositeOperation === undefined) {\n options.compositeOperation = this.compositeOperation;\n }\n if (options.crossOriginPolicy === undefined) {\n options.crossOriginPolicy = options.tileSource.crossOriginPolicy !== undefined ? options.tileSource.crossOriginPolicy : this.crossOriginPolicy;\n }\n if (options.ajaxWithCredentials === undefined) {\n options.ajaxWithCredentials = this.ajaxWithCredentials;\n }\n if (options.loadTilesWithAjax === undefined) {\n options.loadTilesWithAjax = this.loadTilesWithAjax;\n }\n if (options.ajaxHeaders === undefined || options.ajaxHeaders === null) {\n options.ajaxHeaders = this.ajaxHeaders;\n } else if ($.isPlainObject(options.ajaxHeaders) && $.isPlainObject(this.ajaxHeaders)) {\n options.ajaxHeaders = $.extend({}, this.ajaxHeaders, options.ajaxHeaders);\n }\n\n var myQueueItem = {\n options: options\n };\n\n function raiseAddItemFailed( event ) {\n for (var i = 0; i < _this._loadQueue.length; i++) {\n if (_this._loadQueue[i] === myQueueItem) {\n _this._loadQueue.splice(i, 1);\n break;\n }\n }\n\n if (_this._loadQueue.length === 0) {\n refreshWorld(myQueueItem);\n }\n\n /**\n * Raised when an error occurs while adding a item.\n * @event add-item-failed\n * @memberOf OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {String} message\n * @property {String} source\n * @property {Object} options The options passed to the addTiledImage method.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( 'add-item-failed', event );\n\n if (options.error) {\n options.error(event);\n }\n }\n\n function refreshWorld(theItem) {\n if (_this.collectionMode) {\n _this.world.arrange({\n immediately: theItem.options.collectionImmediately,\n rows: _this.collectionRows,\n columns: _this.collectionColumns,\n layout: _this.collectionLayout,\n tileSize: _this.collectionTileSize,\n tileMargin: _this.collectionTileMargin\n });\n _this.world.setAutoRefigureSizes(true);\n }\n }\n\n if ($.isArray(options.tileSource)) {\n setTimeout(function() {\n raiseAddItemFailed({\n message: \"[Viewer.addTiledImage] Sequences can not be added; add them one at a time instead.\",\n source: options.tileSource,\n options: options\n });\n });\n return;\n }\n\n this._loadQueue.push(myQueueItem);\n\n function processReadyItems() {\n var queueItem, tiledImage, optionsClone;\n while (_this._loadQueue.length) {\n queueItem = _this._loadQueue[0];\n if (!queueItem.tileSource) {\n break;\n }\n\n _this._loadQueue.splice(0, 1);\n\n if (queueItem.options.replace) {\n var newIndex = _this.world.getIndexOfItem(queueItem.options.replaceItem);\n if (newIndex != -1) {\n queueItem.options.index = newIndex;\n }\n _this.world.removeItem(queueItem.options.replaceItem);\n }\n\n tiledImage = new $.TiledImage({\n viewer: _this,\n source: queueItem.tileSource,\n viewport: _this.viewport,\n drawer: _this.drawer,\n tileCache: _this.tileCache,\n imageLoader: _this.imageLoader,\n x: queueItem.options.x,\n y: queueItem.options.y,\n width: queueItem.options.width,\n height: queueItem.options.height,\n fitBounds: queueItem.options.fitBounds,\n fitBoundsPlacement: queueItem.options.fitBoundsPlacement,\n clip: queueItem.options.clip,\n placeholderFillStyle: queueItem.options.placeholderFillStyle,\n opacity: queueItem.options.opacity,\n preload: queueItem.options.preload,\n degrees: queueItem.options.degrees,\n compositeOperation: queueItem.options.compositeOperation,\n springStiffness: _this.springStiffness,\n animationTime: _this.animationTime,\n minZoomImageRatio: _this.minZoomImageRatio,\n wrapHorizontal: _this.wrapHorizontal,\n wrapVertical: _this.wrapVertical,\n immediateRender: _this.immediateRender,\n blendTime: _this.blendTime,\n alwaysBlend: _this.alwaysBlend,\n minPixelRatio: _this.minPixelRatio,\n smoothTileEdgesMinZoom: _this.smoothTileEdgesMinZoom,\n iOSDevice: _this.iOSDevice,\n crossOriginPolicy: queueItem.options.crossOriginPolicy,\n ajaxWithCredentials: queueItem.options.ajaxWithCredentials,\n loadTilesWithAjax: queueItem.options.loadTilesWithAjax,\n ajaxHeaders: queueItem.options.ajaxHeaders,\n debugMode: _this.debugMode\n });\n\n if (_this.collectionMode) {\n _this.world.setAutoRefigureSizes(false);\n }\n _this.world.addItem( tiledImage, {\n index: queueItem.options.index\n });\n\n if (_this._loadQueue.length === 0) {\n //this restores the autoRefigureSizes flag to true.\n refreshWorld(queueItem);\n }\n\n if (_this.world.getItemCount() === 1 && !_this.preserveViewport) {\n _this.viewport.goHome(true);\n }\n\n if (_this.navigator) {\n optionsClone = $.extend({}, queueItem.options, {\n replace: false, // navigator already removed the layer, nothing to replace\n originalTiledImage: tiledImage,\n tileSource: queueItem.tileSource\n });\n\n _this.navigator.addTiledImage(optionsClone);\n }\n\n if (queueItem.options.success) {\n queueItem.options.success({\n item: tiledImage\n });\n }\n }\n }\n\n getTileSourceImplementation( this, options.tileSource, options, function( tileSource ) {\n\n myQueueItem.tileSource = tileSource;\n\n // add everybody at the front of the queue that's ready to go\n processReadyItems();\n }, function( event ) {\n event.options = options;\n raiseAddItemFailed(event);\n\n // add everybody at the front of the queue that's ready to go\n processReadyItems();\n } );\n },\n\n /**\n * Add a simple image to the viewer.\n * The options are the same as the ones in {@link OpenSeadragon.Viewer#addTiledImage}\n * except for options.tileSource which is replaced by options.url.\n * @function\n * @param {Object} options - See {@link OpenSeadragon.Viewer#addTiledImage}\n * for all the options\n * @param {String} options.url - The URL of the image to add.\n * @fires OpenSeadragon.World.event:add-item\n * @fires OpenSeadragon.Viewer.event:add-item-failed\n */\n addSimpleImage: function(options) {\n $.console.assert(options, \"[Viewer.addSimpleImage] options is required\");\n $.console.assert(options.url, \"[Viewer.addSimpleImage] options.url is required\");\n\n var opts = $.extend({}, options, {\n tileSource: {\n type: 'image',\n url: options.url\n }\n });\n delete opts.url;\n this.addTiledImage(opts);\n },\n\n // deprecated\n addLayer: function( options ) {\n var _this = this;\n\n $.console.error( \"[Viewer.addLayer] this function is deprecated; use Viewer.addTiledImage() instead.\" );\n\n var optionsClone = $.extend({}, options, {\n success: function(event) {\n _this.raiseEvent(\"add-layer\", {\n options: options,\n drawer: event.item\n });\n },\n error: function(event) {\n _this.raiseEvent(\"add-layer-failed\", event);\n }\n });\n\n this.addTiledImage(optionsClone);\n return this;\n },\n\n // deprecated\n getLayerAtLevel: function( level ) {\n $.console.error( \"[Viewer.getLayerAtLevel] this function is deprecated; use World.getItemAt() instead.\" );\n return this.world.getItemAt(level);\n },\n\n // deprecated\n getLevelOfLayer: function( drawer ) {\n $.console.error( \"[Viewer.getLevelOfLayer] this function is deprecated; use World.getIndexOfItem() instead.\" );\n return this.world.getIndexOfItem(drawer);\n },\n\n // deprecated\n getLayersCount: function() {\n $.console.error( \"[Viewer.getLayersCount] this function is deprecated; use World.getItemCount() instead.\" );\n return this.world.getItemCount();\n },\n\n // deprecated\n setLayerLevel: function( drawer, level ) {\n $.console.error( \"[Viewer.setLayerLevel] this function is deprecated; use World.setItemIndex() instead.\" );\n return this.world.setItemIndex(drawer, level);\n },\n\n // deprecated\n removeLayer: function( drawer ) {\n $.console.error( \"[Viewer.removeLayer] this function is deprecated; use World.removeItem() instead.\" );\n return this.world.removeItem(drawer);\n },\n\n /**\n * Force the viewer to redraw its contents.\n * @returns {OpenSeadragon.Viewer} Chainable.\n */\n forceRedraw: function() {\n THIS[ this.hash ].forceRedraw = true;\n return this;\n },\n\n /**\n * @function\n * @return {OpenSeadragon.Viewer} Chainable.\n */\n bindSequenceControls: function(){\n\n //////////////////////////////////////////////////////////////////////////\n // Image Sequence Controls\n //////////////////////////////////////////////////////////////////////////\n var onFocusHandler = $.delegate( this, onFocus ),\n onBlurHandler = $.delegate( this, onBlur ),\n onNextHandler = $.delegate( this, onNext ),\n onPreviousHandler = $.delegate( this, onPrevious ),\n navImages = this.navImages,\n useGroup = true;\n\n if( this.showSequenceControl ){\n\n if( this.previousButton || this.nextButton ){\n //if we are binding to custom buttons then layout and\n //grouping is the responsibility of the page author\n useGroup = false;\n }\n\n this.previousButton = new $.Button({\n element: this.previousButton ? $.getElement( this.previousButton ) : null,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n tooltip: $.getString( \"Tooltips.PreviousPage\" ),\n srcRest: resolveUrl( this.prefixUrl, navImages.previous.REST ),\n srcGroup: resolveUrl( this.prefixUrl, navImages.previous.GROUP ),\n srcHover: resolveUrl( this.prefixUrl, navImages.previous.HOVER ),\n srcDown: resolveUrl( this.prefixUrl, navImages.previous.DOWN ),\n onRelease: onPreviousHandler,\n onFocus: onFocusHandler,\n onBlur: onBlurHandler\n });\n\n this.nextButton = new $.Button({\n element: this.nextButton ? $.getElement( this.nextButton ) : null,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n tooltip: $.getString( \"Tooltips.NextPage\" ),\n srcRest: resolveUrl( this.prefixUrl, navImages.next.REST ),\n srcGroup: resolveUrl( this.prefixUrl, navImages.next.GROUP ),\n srcHover: resolveUrl( this.prefixUrl, navImages.next.HOVER ),\n srcDown: resolveUrl( this.prefixUrl, navImages.next.DOWN ),\n onRelease: onNextHandler,\n onFocus: onFocusHandler,\n onBlur: onBlurHandler\n });\n\n if( !this.navPrevNextWrap ){\n this.previousButton.disable();\n }\n\n if (!this.tileSources || !this.tileSources.length) {\n this.nextButton.disable();\n }\n\n if( useGroup ){\n this.paging = new $.ButtonGroup({\n buttons: [\n this.previousButton,\n this.nextButton\n ],\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold\n });\n\n this.pagingControl = this.paging.element;\n\n if( this.toolbar ){\n this.toolbar.addControl(\n this.pagingControl,\n {anchor: $.ControlAnchor.BOTTOM_RIGHT}\n );\n }else{\n this.addControl(\n this.pagingControl,\n {anchor: this.sequenceControlAnchor || $.ControlAnchor.TOP_LEFT}\n );\n }\n }\n }\n return this;\n },\n\n\n /**\n * @function\n * @return {OpenSeadragon.Viewer} Chainable.\n */\n bindStandardControls: function(){\n //////////////////////////////////////////////////////////////////////////\n // Navigation Controls\n //////////////////////////////////////////////////////////////////////////\n var beginZoomingInHandler = $.delegate( this, beginZoomingIn ),\n endZoomingHandler = $.delegate( this, endZooming ),\n doSingleZoomInHandler = $.delegate( this, doSingleZoomIn ),\n beginZoomingOutHandler = $.delegate( this, beginZoomingOut ),\n doSingleZoomOutHandler = $.delegate( this, doSingleZoomOut ),\n onHomeHandler = $.delegate( this, onHome ),\n onFullScreenHandler = $.delegate( this, onFullScreen ),\n onRotateLeftHandler = $.delegate( this, onRotateLeft ),\n onRotateRightHandler = $.delegate( this, onRotateRight ),\n onFocusHandler = $.delegate( this, onFocus ),\n onBlurHandler = $.delegate( this, onBlur ),\n navImages = this.navImages,\n buttons = [],\n useGroup = true;\n\n\n if ( this.showNavigationControl ) {\n\n if( this.zoomInButton || this.zoomOutButton ||\n this.homeButton || this.fullPageButton ||\n this.rotateLeftButton || this.rotateRightButton ) {\n //if we are binding to custom buttons then layout and\n //grouping is the responsibility of the page author\n useGroup = false;\n }\n\n if ( this.showZoomControl ) {\n buttons.push( this.zoomInButton = new $.Button({\n element: this.zoomInButton ? $.getElement( this.zoomInButton ) : null,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n tooltip: $.getString( \"Tooltips.ZoomIn\" ),\n srcRest: resolveUrl( this.prefixUrl, navImages.zoomIn.REST ),\n srcGroup: resolveUrl( this.prefixUrl, navImages.zoomIn.GROUP ),\n srcHover: resolveUrl( this.prefixUrl, navImages.zoomIn.HOVER ),\n srcDown: resolveUrl( this.prefixUrl, navImages.zoomIn.DOWN ),\n onPress: beginZoomingInHandler,\n onRelease: endZoomingHandler,\n onClick: doSingleZoomInHandler,\n onEnter: beginZoomingInHandler,\n onExit: endZoomingHandler,\n onFocus: onFocusHandler,\n onBlur: onBlurHandler\n }));\n\n buttons.push( this.zoomOutButton = new $.Button({\n element: this.zoomOutButton ? $.getElement( this.zoomOutButton ) : null,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n tooltip: $.getString( \"Tooltips.ZoomOut\" ),\n srcRest: resolveUrl( this.prefixUrl, navImages.zoomOut.REST ),\n srcGroup: resolveUrl( this.prefixUrl, navImages.zoomOut.GROUP ),\n srcHover: resolveUrl( this.prefixUrl, navImages.zoomOut.HOVER ),\n srcDown: resolveUrl( this.prefixUrl, navImages.zoomOut.DOWN ),\n onPress: beginZoomingOutHandler,\n onRelease: endZoomingHandler,\n onClick: doSingleZoomOutHandler,\n onEnter: beginZoomingOutHandler,\n onExit: endZoomingHandler,\n onFocus: onFocusHandler,\n onBlur: onBlurHandler\n }));\n }\n\n if ( this.showHomeControl ) {\n buttons.push( this.homeButton = new $.Button({\n element: this.homeButton ? $.getElement( this.homeButton ) : null,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n tooltip: $.getString( \"Tooltips.Home\" ),\n srcRest: resolveUrl( this.prefixUrl, navImages.home.REST ),\n srcGroup: resolveUrl( this.prefixUrl, navImages.home.GROUP ),\n srcHover: resolveUrl( this.prefixUrl, navImages.home.HOVER ),\n srcDown: resolveUrl( this.prefixUrl, navImages.home.DOWN ),\n onRelease: onHomeHandler,\n onFocus: onFocusHandler,\n onBlur: onBlurHandler\n }));\n }\n\n if ( this.showFullPageControl ) {\n buttons.push( this.fullPageButton = new $.Button({\n element: this.fullPageButton ? $.getElement( this.fullPageButton ) : null,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n tooltip: $.getString( \"Tooltips.FullPage\" ),\n srcRest: resolveUrl( this.prefixUrl, navImages.fullpage.REST ),\n srcGroup: resolveUrl( this.prefixUrl, navImages.fullpage.GROUP ),\n srcHover: resolveUrl( this.prefixUrl, navImages.fullpage.HOVER ),\n srcDown: resolveUrl( this.prefixUrl, navImages.fullpage.DOWN ),\n onRelease: onFullScreenHandler,\n onFocus: onFocusHandler,\n onBlur: onBlurHandler\n }));\n }\n\n if ( this.showRotationControl ) {\n buttons.push( this.rotateLeftButton = new $.Button({\n element: this.rotateLeftButton ? $.getElement( this.rotateLeftButton ) : null,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n tooltip: $.getString( \"Tooltips.RotateLeft\" ),\n srcRest: resolveUrl( this.prefixUrl, navImages.rotateleft.REST ),\n srcGroup: resolveUrl( this.prefixUrl, navImages.rotateleft.GROUP ),\n srcHover: resolveUrl( this.prefixUrl, navImages.rotateleft.HOVER ),\n srcDown: resolveUrl( this.prefixUrl, navImages.rotateleft.DOWN ),\n onRelease: onRotateLeftHandler,\n onFocus: onFocusHandler,\n onBlur: onBlurHandler\n }));\n\n buttons.push( this.rotateRightButton = new $.Button({\n element: this.rotateRightButton ? $.getElement( this.rotateRightButton ) : null,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n tooltip: $.getString( \"Tooltips.RotateRight\" ),\n srcRest: resolveUrl( this.prefixUrl, navImages.rotateright.REST ),\n srcGroup: resolveUrl( this.prefixUrl, navImages.rotateright.GROUP ),\n srcHover: resolveUrl( this.prefixUrl, navImages.rotateright.HOVER ),\n srcDown: resolveUrl( this.prefixUrl, navImages.rotateright.DOWN ),\n onRelease: onRotateRightHandler,\n onFocus: onFocusHandler,\n onBlur: onBlurHandler\n }));\n\n }\n\n if ( useGroup ) {\n this.buttons = new $.ButtonGroup({\n buttons: buttons,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold\n });\n\n this.navControl = this.buttons.element;\n this.addHandler( 'open', $.delegate( this, lightUp ) );\n\n if( this.toolbar ){\n this.toolbar.addControl(\n this.navControl,\n {anchor: this.navigationControlAnchor || $.ControlAnchor.TOP_LEFT}\n );\n } else {\n this.addControl(\n this.navControl,\n {anchor: this.navigationControlAnchor || $.ControlAnchor.TOP_LEFT}\n );\n }\n }\n\n }\n return this;\n },\n\n /**\n * Gets the active page of a sequence\n * @function\n * @return {Number}\n */\n currentPage: function() {\n return this._sequenceIndex;\n },\n\n /**\n * @function\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:page\n */\n goToPage: function( page ){\n if( this.tileSources && page >= 0 && page < this.tileSources.length ){\n /**\n * Raised when the page is changed on a viewer configured with multiple image sources (see {@link OpenSeadragon.Viewer#goToPage}).\n *\n * @event page\n * @memberof OpenSeadragon.Viewer\n * @type {Object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Number} page - The page index.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'page', { page: page } );\n\n this._sequenceIndex = page;\n\n this._updateSequenceButtons( page );\n\n this.open( this.tileSources[ page ] );\n\n if( this.referenceStrip ){\n this.referenceStrip.setFocus( page );\n }\n }\n\n return this;\n },\n\n /**\n * Adds an html element as an overlay to the current viewport. Useful for\n * highlighting words or areas of interest on an image or other zoomable\n * interface. The overlays added via this method are removed when the viewport\n * is closed which include when changing page.\n * @method\n * @param {Element|String|Object} element - A reference to an element or an id for\n * the element which will be overlayed. Or an Object specifying the configuration for the overlay.\n * If using an object, see {@link OpenSeadragon.Overlay} for a list of\n * all available options.\n * @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or\n * rectangle which will be overlayed. This is a viewport relative location.\n * @param {OpenSeadragon.Placement} placement - The position of the\n * viewport which the location coordinates will be treated as relative\n * to.\n * @param {function} onDraw - If supplied the callback is called when the overlay\n * needs to be drawn. It it the responsibility of the callback to do any drawing/positioning.\n * It is passed position, size and element.\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:add-overlay\n */\n addOverlay: function( element, location, placement, onDraw ) {\n var options;\n if( $.isPlainObject( element ) ){\n options = element;\n } else {\n options = {\n element: element,\n location: location,\n placement: placement,\n onDraw: onDraw\n };\n }\n\n element = $.getElement( options.element );\n\n if ( getOverlayIndex( this.currentOverlays, element ) >= 0 ) {\n // they're trying to add a duplicate overlay\n return this;\n }\n\n var overlay = getOverlayObject( this, options);\n this.currentOverlays.push(overlay);\n overlay.drawHTML( this.overlaysContainer, this.viewport );\n\n /**\n * Raised when an overlay is added to the viewer (see {@link OpenSeadragon.Viewer#addOverlay}).\n *\n * @event add-overlay\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Element} element - The overlay element.\n * @property {OpenSeadragon.Point|OpenSeadragon.Rect} location\n * @property {OpenSeadragon.Placement} placement\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'add-overlay', {\n element: element,\n location: options.location,\n placement: options.placement\n });\n return this;\n },\n\n /**\n * Updates the overlay represented by the reference to the element or\n * element id moving it to the new location, relative to the new placement.\n * @method\n * @param {Element|String} element - A reference to an element or an id for\n * the element which is overlayed.\n * @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or\n * rectangle which will be overlayed. This is a viewport relative location.\n * @param {OpenSeadragon.Placement} placement - The position of the\n * viewport which the location coordinates will be treated as relative\n * to.\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:update-overlay\n */\n updateOverlay: function( element, location, placement ) {\n var i;\n\n element = $.getElement( element );\n i = getOverlayIndex( this.currentOverlays, element );\n\n if ( i >= 0 ) {\n this.currentOverlays[ i ].update( location, placement );\n THIS[ this.hash ].forceRedraw = true;\n /**\n * Raised when an overlay's location or placement changes\n * (see {@link OpenSeadragon.Viewer#updateOverlay}).\n *\n * @event update-overlay\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the\n * Viewer which raised the event.\n * @property {Element} element\n * @property {OpenSeadragon.Point|OpenSeadragon.Rect} location\n * @property {OpenSeadragon.Placement} placement\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'update-overlay', {\n element: element,\n location: location,\n placement: placement\n });\n }\n return this;\n },\n\n /**\n * Removes an overlay identified by the reference element or element id\n * and schedules an update.\n * @method\n * @param {Element|String} element - A reference to the element or an\n * element id which represent the ovelay content to be removed.\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:remove-overlay\n */\n removeOverlay: function( element ) {\n var i;\n\n element = $.getElement( element );\n i = getOverlayIndex( this.currentOverlays, element );\n\n if ( i >= 0 ) {\n this.currentOverlays[ i ].destroy();\n this.currentOverlays.splice( i, 1 );\n THIS[ this.hash ].forceRedraw = true;\n /**\n * Raised when an overlay is removed from the viewer\n * (see {@link OpenSeadragon.Viewer#removeOverlay}).\n *\n * @event remove-overlay\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the\n * Viewer which raised the event.\n * @property {Element} element - The overlay element.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'remove-overlay', {\n element: element\n });\n }\n return this;\n },\n\n /**\n * Removes all currently configured Overlays from this Viewer and schedules\n * an update.\n * @method\n * @return {OpenSeadragon.Viewer} Chainable.\n * @fires OpenSeadragon.Viewer.event:clear-overlay\n */\n clearOverlays: function() {\n while ( this.currentOverlays.length > 0 ) {\n this.currentOverlays.pop().destroy();\n }\n THIS[ this.hash ].forceRedraw = true;\n /**\n * Raised when all overlays are removed from the viewer (see {@link OpenSeadragon.Drawer#clearOverlays}).\n *\n * @event clear-overlay\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'clear-overlay', {} );\n return this;\n },\n\n /**\n * Finds an overlay identified by the reference element or element id\n * and returns it as an object, return null if not found.\n * @method\n * @param {Element|String} element - A reference to the element or an\n * element id which represents the overlay content.\n * @return {OpenSeadragon.Overlay} the matching overlay or null if none found.\n */\n getOverlayById: function( element ) {\n var i;\n\n element = $.getElement( element );\n i = getOverlayIndex( this.currentOverlays, element );\n\n if (i >= 0) {\n return this.currentOverlays[i];\n } else {\n return null;\n }\n },\n\n /**\n * Updates the sequence buttons.\n * @function OpenSeadragon.Viewer.prototype._updateSequenceButtons\n * @private\n * @param {Number} Sequence Value\n */\n _updateSequenceButtons: function( page ) {\n\n if ( this.nextButton ) {\n if(!this.tileSources || this.tileSources.length - 1 === page) {\n //Disable next button\n if ( !this.navPrevNextWrap ) {\n this.nextButton.disable();\n }\n } else {\n this.nextButton.enable();\n }\n }\n if ( this.previousButton ) {\n if ( page > 0 ) {\n //Enable previous button\n this.previousButton.enable();\n } else {\n if ( !this.navPrevNextWrap ) {\n this.previousButton.disable();\n }\n }\n }\n },\n\n /**\n * Display a message in the viewport\n * @function OpenSeadragon.Viewer.prototype._showMessage\n * @private\n * @param {String} text message\n */\n _showMessage: function ( message ) {\n this._hideMessage();\n\n var div = $.makeNeutralElement( \"div\" );\n div.appendChild( document.createTextNode( message ) );\n\n this.messageDiv = $.makeCenteredNode( div );\n\n $.addClass(this.messageDiv, \"openseadragon-message\");\n\n this.container.appendChild( this.messageDiv );\n },\n\n /**\n * Hide any currently displayed viewport message\n * @function OpenSeadragon.Viewer.prototype._hideMessage\n * @private\n */\n _hideMessage: function () {\n var div = this.messageDiv;\n if (div) {\n div.parentNode.removeChild(div);\n delete this.messageDiv;\n }\n },\n\n /**\n * Gets this viewer's gesture settings for the given pointer device type.\n * @method\n * @param {String} type - The pointer device type to get the gesture settings for (\"mouse\", \"touch\", \"pen\", etc.).\n * @return {OpenSeadragon.GestureSettings}\n */\n gestureSettingsByDeviceType: function ( type ) {\n switch ( type ) {\n case 'mouse':\n return this.gestureSettingsMouse;\n case 'touch':\n return this.gestureSettingsTouch;\n case 'pen':\n return this.gestureSettingsPen;\n default:\n return this.gestureSettingsUnknown;\n }\n },\n\n // private\n _drawOverlays: function() {\n var i,\n length = this.currentOverlays.length;\n for ( i = 0; i < length; i++ ) {\n this.currentOverlays[ i ].drawHTML( this.overlaysContainer, this.viewport );\n }\n },\n\n /**\n * Cancel the \"in flight\" images.\n */\n _cancelPendingImages: function() {\n this._loadQueue = [];\n },\n\n /**\n * Removes the reference strip and disables displaying it.\n * @function\n */\n removeReferenceStrip: function() {\n this.showReferenceStrip = false;\n\n if (this.referenceStrip) {\n this.referenceStrip.destroy();\n this.referenceStrip = null;\n }\n },\n\n /**\n * Enables and displays the reference strip based on the currently set tileSources.\n * Works only when the Viewer has sequenceMode set to true.\n * @function\n */\n addReferenceStrip: function() {\n this.showReferenceStrip = true;\n\n if (this.sequenceMode) {\n if (this.referenceStrip) {\n return;\n }\n\n if (this.tileSources.length && this.tileSources.length > 1) {\n this.referenceStrip = new $.ReferenceStrip({\n id: this.referenceStripElement,\n position: this.referenceStripPosition,\n sizeRatio: this.referenceStripSizeRatio,\n scroll: this.referenceStripScroll,\n height: this.referenceStripHeight,\n width: this.referenceStripWidth,\n tileSources: this.tileSources,\n prefixUrl: this.prefixUrl,\n viewer: this\n });\n\n this.referenceStrip.setFocus( this._sequenceIndex );\n }\n } else {\n $.console.warn('Attempting to display a reference strip while \"sequenceMode\" is off.');\n }\n }\n});\n\n\n/**\n * _getSafeElemSize is like getElementSize(), but refuses to return 0 for x or y,\n * which was causing some calling operations to return NaN.\n * @returns {Point}\n * @private\n */\nfunction _getSafeElemSize (oElement) {\n oElement = $.getElement( oElement );\n\n return new $.Point(\n (oElement.clientWidth === 0 ? 1 : oElement.clientWidth),\n (oElement.clientHeight === 0 ? 1 : oElement.clientHeight)\n );\n}\n\n\n/**\n * @function\n * @private\n */\nfunction getTileSourceImplementation( viewer, tileSource, imgOptions, successCallback,\n failCallback ) {\n var _this = viewer;\n\n //allow plain xml strings or json strings to be parsed here\n if ( $.type( tileSource ) == 'string' ) {\n //xml should start with \"<\" and end with \">\"\n if ( tileSource.match( /^\\s*<.*>\\s*$/ ) ) {\n tileSource = $.parseXml( tileSource );\n //json should start with \"{\" or \"[\" and end with \"}\" or \"]\"\n } else if ( tileSource.match(/^\\s*[\\{\\[].*[\\}\\]]\\s*$/ ) ) {\n try {\n var tileSourceJ = $.parseJSON(tileSource);\n tileSource = tileSourceJ;\n } catch (e) {\n //tileSource = tileSource;\n }\n }\n }\n\n function waitUntilReady(tileSource, originalTileSource) {\n if (tileSource.ready) {\n successCallback(tileSource);\n } else {\n tileSource.addHandler('ready', function () {\n successCallback(tileSource);\n });\n tileSource.addHandler('open-failed', function (event) {\n failCallback({\n message: event.message,\n source: originalTileSource\n });\n });\n }\n }\n\n setTimeout( function() {\n if ( $.type( tileSource ) == 'string' ) {\n //If its still a string it means it must be a url at this point\n tileSource = new $.TileSource({\n url: tileSource,\n crossOriginPolicy: imgOptions.crossOriginPolicy !== undefined ?\n imgOptions.crossOriginPolicy : viewer.crossOriginPolicy,\n ajaxWithCredentials: viewer.ajaxWithCredentials,\n ajaxHeaders: viewer.ajaxHeaders,\n useCanvas: viewer.useCanvas,\n success: function( event ) {\n successCallback( event.tileSource );\n }\n });\n tileSource.addHandler( 'open-failed', function( event ) {\n failCallback( event );\n } );\n\n } else if ($.isPlainObject(tileSource) || tileSource.nodeType) {\n if (tileSource.crossOriginPolicy === undefined &&\n (imgOptions.crossOriginPolicy !== undefined || viewer.crossOriginPolicy !== undefined)) {\n tileSource.crossOriginPolicy = imgOptions.crossOriginPolicy !== undefined ?\n imgOptions.crossOriginPolicy : viewer.crossOriginPolicy;\n }\n if (tileSource.ajaxWithCredentials === undefined) {\n tileSource.ajaxWithCredentials = viewer.ajaxWithCredentials;\n }\n if (tileSource.useCanvas === undefined) {\n tileSource.useCanvas = viewer.useCanvas;\n }\n\n if ( $.isFunction( tileSource.getTileUrl ) ) {\n //Custom tile source\n var customTileSource = new $.TileSource( tileSource );\n customTileSource.getTileUrl = tileSource.getTileUrl;\n successCallback( customTileSource );\n } else {\n //inline configuration\n var $TileSource = $.TileSource.determineType( _this, tileSource );\n if ( !$TileSource ) {\n failCallback( {\n message: \"Unable to load TileSource\",\n source: tileSource\n });\n return;\n }\n var options = $TileSource.prototype.configure.apply( _this, [ tileSource ] );\n waitUntilReady(new $TileSource(options), tileSource);\n }\n } else {\n //can assume it's already a tile source implementation\n waitUntilReady(tileSource, tileSource);\n }\n });\n}\n\nfunction getOverlayObject( viewer, overlay ) {\n if ( overlay instanceof $.Overlay ) {\n return overlay;\n }\n\n var element = null;\n if ( overlay.element ) {\n element = $.getElement( overlay.element );\n } else {\n var id = overlay.id ?\n overlay.id :\n \"openseadragon-overlay-\" + Math.floor( Math.random() * 10000000 );\n\n element = $.getElement( overlay.id );\n if ( !element ) {\n element = document.createElement( \"a\" );\n element.href = \"#/overlay/\" + id;\n }\n element.id = id;\n $.addClass( element, overlay.className ?\n overlay.className :\n \"openseadragon-overlay\"\n );\n }\n\n var location = overlay.location;\n var width = overlay.width;\n var height = overlay.height;\n if (!location) {\n var x = overlay.x;\n var y = overlay.y;\n if (overlay.px !== undefined) {\n var rect = viewer.viewport.imageToViewportRectangle(new $.Rect(\n overlay.px,\n overlay.py,\n width || 0,\n height || 0));\n x = rect.x;\n y = rect.y;\n width = width !== undefined ? rect.width : undefined;\n height = height !== undefined ? rect.height : undefined;\n }\n location = new $.Point(x, y);\n }\n\n var placement = overlay.placement;\n if (placement && $.type(placement) === \"string\") {\n placement = $.Placement[overlay.placement.toUpperCase()];\n }\n\n return new $.Overlay({\n element: element,\n location: location,\n placement: placement,\n onDraw: overlay.onDraw,\n checkResize: overlay.checkResize,\n width: width,\n height: height,\n rotationMode: overlay.rotationMode\n });\n}\n\n/**\n * @private\n * @inner\n * Determines the index of the given overlay in the given overlays array.\n */\nfunction getOverlayIndex( overlays, element ) {\n var i;\n for ( i = overlays.length - 1; i >= 0; i-- ) {\n if ( overlays[ i ].element === element ) {\n return i;\n }\n }\n\n return -1;\n}\n\n///////////////////////////////////////////////////////////////////////////////\n// Schedulers provide the general engine for animation\n///////////////////////////////////////////////////////////////////////////////\nfunction scheduleUpdate( viewer, updateFunc ){\n return $.requestAnimationFrame( function(){\n updateFunc( viewer );\n } );\n}\n\n\n//provides a sequence in the fade animation\nfunction scheduleControlsFade( viewer ) {\n $.requestAnimationFrame( function(){\n updateControlsFade( viewer );\n });\n}\n\n\n//initiates an animation to hide the controls\nfunction beginControlsAutoHide( viewer ) {\n if ( !viewer.autoHideControls ) {\n return;\n }\n viewer.controlsShouldFade = true;\n viewer.controlsFadeBeginTime =\n $.now() +\n viewer.controlsFadeDelay;\n\n window.setTimeout( function(){\n scheduleControlsFade( viewer );\n }, viewer.controlsFadeDelay );\n}\n\n\n//determines if fade animation is done or continues the animation\nfunction updateControlsFade( viewer ) {\n var currentTime,\n deltaTime,\n opacity,\n i;\n if ( viewer.controlsShouldFade ) {\n currentTime = $.now();\n deltaTime = currentTime - viewer.controlsFadeBeginTime;\n opacity = 1.0 - deltaTime / viewer.controlsFadeLength;\n\n opacity = Math.min( 1.0, opacity );\n opacity = Math.max( 0.0, opacity );\n\n for ( i = viewer.controls.length - 1; i >= 0; i--) {\n if (viewer.controls[ i ].autoFade) {\n viewer.controls[ i ].setOpacity( opacity );\n }\n }\n\n if ( opacity > 0 ) {\n // fade again\n scheduleControlsFade( viewer );\n }\n }\n}\n\n\n//stop the fade animation on the controls and show them\nfunction abortControlsAutoHide( viewer ) {\n var i;\n viewer.controlsShouldFade = false;\n for ( i = viewer.controls.length - 1; i >= 0; i-- ) {\n viewer.controls[ i ].setOpacity( 1.0 );\n }\n}\n\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Default view event handlers.\n///////////////////////////////////////////////////////////////////////////////\nfunction onFocus(){\n abortControlsAutoHide( this );\n}\n\nfunction onBlur(){\n beginControlsAutoHide( this );\n\n}\n\nfunction onCanvasKeyDown( event ) {\n if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) {\n switch( event.keyCode ){\n case 38://up arrow\n if ( event.shift ) {\n this.viewport.zoomBy(1.1);\n } else {\n this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, -40)));\n }\n this.viewport.applyConstraints();\n return false;\n case 40://down arrow\n if ( event.shift ) {\n this.viewport.zoomBy(0.9);\n } else {\n this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, 40)));\n }\n this.viewport.applyConstraints();\n return false;\n case 37://left arrow\n this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(-40, 0)));\n this.viewport.applyConstraints();\n return false;\n case 39://right arrow\n this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(40, 0)));\n this.viewport.applyConstraints();\n return false;\n default:\n //console.log( 'navigator keycode %s', event.keyCode );\n return true;\n }\n } else {\n return true;\n }\n}\n\nfunction onCanvasKeyPress( event ) {\n if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) {\n switch( event.keyCode ){\n case 43://=|+\n case 61://=|+\n this.viewport.zoomBy(1.1);\n this.viewport.applyConstraints();\n return false;\n case 45://-|_\n this.viewport.zoomBy(0.9);\n this.viewport.applyConstraints();\n return false;\n case 48://0|)\n this.viewport.goHome();\n this.viewport.applyConstraints();\n return false;\n case 119://w\n case 87://W\n if ( event.shift ) {\n this.viewport.zoomBy(1.1);\n } else {\n this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, -40)));\n }\n this.viewport.applyConstraints();\n return false;\n case 115://s\n case 83://S\n if ( event.shift ) {\n this.viewport.zoomBy(0.9);\n } else {\n this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, 40)));\n }\n this.viewport.applyConstraints();\n return false;\n case 97://a\n this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(-40, 0)));\n this.viewport.applyConstraints();\n return false;\n case 100://d\n this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(40, 0)));\n this.viewport.applyConstraints();\n return false;\n default:\n //console.log( 'navigator keycode %s', event.keyCode );\n return true;\n }\n } else {\n return true;\n }\n}\n\nfunction onCanvasClick( event ) {\n var gestureSettings;\n\n var haveKeyboardFocus = document.activeElement == this.canvas;\n\n // If we don't have keyboard focus, request it.\n if ( !haveKeyboardFocus ) {\n this.canvas.focus();\n }\n\n var canvasClickEventArgs = {\n tracker: event.eventSource,\n position: event.position,\n quick: event.quick,\n shift: event.shift,\n originalEvent: event.originalEvent,\n preventDefaultAction: event.preventDefaultAction\n };\n\n /**\n * Raised when a mouse press/release or touch/remove occurs on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-click\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Boolean} quick - True only if the clickDistThreshold and clickTimeThreshold are both passed. Useful for differentiating between clicks and drags.\n * @property {Boolean} shift - True if the shift key was pressed during this event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {Boolean} preventDefaultAction - Set to true to prevent default click to zoom behaviour. Default: false.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-click', canvasClickEventArgs);\n\n if ( !canvasClickEventArgs.preventDefaultAction && this.viewport && event.quick ) {\n gestureSettings = this.gestureSettingsByDeviceType( event.pointerType );\n if ( gestureSettings.clickToZoom ) {\n this.viewport.zoomBy(\n event.shift ? 1.0 / this.zoomPerClick : this.zoomPerClick,\n this.viewport.pointFromPixel( event.position, true )\n );\n this.viewport.applyConstraints();\n }\n }\n}\n\nfunction onCanvasDblClick( event ) {\n var gestureSettings;\n\n if ( !event.preventDefaultAction && this.viewport ) {\n gestureSettings = this.gestureSettingsByDeviceType( event.pointerType );\n if ( gestureSettings.dblClickToZoom ) {\n this.viewport.zoomBy(\n event.shift ? 1.0 / this.zoomPerClick : this.zoomPerClick,\n this.viewport.pointFromPixel( event.position, true )\n );\n this.viewport.applyConstraints();\n }\n }\n /**\n * Raised when a double mouse press/release or touch/remove occurs on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-double-click\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Boolean} shift - True if the shift key was pressed during this event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-double-click', {\n tracker: event.eventSource,\n position: event.position,\n shift: event.shift,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onCanvasDrag( event ) {\n var gestureSettings;\n\n var canvasDragEventArgs = {\n tracker: event.eventSource,\n position: event.position,\n delta: event.delta,\n speed: event.speed,\n direction: event.direction,\n shift: event.shift,\n originalEvent: event.originalEvent,\n preventDefaultAction: event.preventDefaultAction\n };\n\n /**\n * Raised when a mouse or touch drag operation occurs on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-drag\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {OpenSeadragon.Point} delta - The x,y components of the difference between start drag and end drag.\n * @property {Number} speed - Current computed speed, in pixels per second.\n * @property {Number} direction - Current computed direction, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0.\n * @property {Boolean} shift - True if the shift key was pressed during this event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {Boolean} preventDefaultAction - Set to true to prevent default drag behaviour. Default: false.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-drag', canvasDragEventArgs);\n\n if ( !canvasDragEventArgs.preventDefaultAction && this.viewport ) {\n gestureSettings = this.gestureSettingsByDeviceType( event.pointerType );\n if( !this.panHorizontal ){\n event.delta.x = 0;\n }\n if( !this.panVertical ){\n event.delta.y = 0;\n }\n\n if( this.constrainDuringPan ){\n var delta = this.viewport.deltaPointsFromPixels( event.delta.negate() );\n\n this.viewport.centerSpringX.target.value += delta.x;\n this.viewport.centerSpringY.target.value += delta.y;\n\n var bounds = this.viewport.getBounds();\n var constrainedBounds = this.viewport.getConstrainedBounds();\n\n this.viewport.centerSpringX.target.value -= delta.x;\n this.viewport.centerSpringY.target.value -= delta.y;\n\n if (bounds.x != constrainedBounds.x) {\n event.delta.x = 0;\n }\n\n if (bounds.y != constrainedBounds.y) {\n event.delta.y = 0;\n }\n }\n\n this.viewport.panBy( this.viewport.deltaPointsFromPixels( event.delta.negate() ), gestureSettings.flickEnabled && !this.constrainDuringPan);\n }\n}\n\nfunction onCanvasDragEnd( event ) {\n if (!event.preventDefaultAction && this.viewport) {\n var gestureSettings = this.gestureSettingsByDeviceType(event.pointerType);\n if (gestureSettings.flickEnabled &&\n event.speed >= gestureSettings.flickMinSpeed) {\n var amplitudeX = 0;\n if (this.panHorizontal) {\n amplitudeX = gestureSettings.flickMomentum * event.speed *\n Math.cos(event.direction);\n }\n var amplitudeY = 0;\n if (this.panVertical) {\n amplitudeY = gestureSettings.flickMomentum * event.speed *\n Math.sin(event.direction);\n }\n var center = this.viewport.pixelFromPoint(\n this.viewport.getCenter(true));\n var target = this.viewport.pointFromPixel(\n new $.Point(center.x - amplitudeX, center.y - amplitudeY));\n this.viewport.panTo(target, false);\n }\n this.viewport.applyConstraints();\n }\n /**\n * Raised when a mouse or touch drag operation ends on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-drag-end\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Number} speed - Speed at the end of a drag gesture, in pixels per second.\n * @property {Number} direction - Direction at the end of a drag gesture, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0.\n * @property {Boolean} shift - True if the shift key was pressed during this event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent('canvas-drag-end', {\n tracker: event.eventSource,\n position: event.position,\n speed: event.speed,\n direction: event.direction,\n shift: event.shift,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onCanvasEnter( event ) {\n /**\n * Raised when a pointer enters the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-enter\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {String} pointerType - \"mouse\", \"touch\", \"pen\", etc.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @property {Number} pointers - Number of pointers (all types) active in the tracked element.\n * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false.\n * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-enter', {\n tracker: event.eventSource,\n pointerType: event.pointerType,\n position: event.position,\n buttons: event.buttons,\n pointers: event.pointers,\n insideElementPressed: event.insideElementPressed,\n buttonDownAny: event.buttonDownAny,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onCanvasExit( event ) {\n\n if (window.location != window.parent.location){\n $.MouseTracker.resetAllMouseTrackers();\n }\n\n /**\n * Raised when a pointer leaves the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-exit\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {String} pointerType - \"mouse\", \"touch\", \"pen\", etc.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @property {Number} pointers - Number of pointers (all types) active in the tracked element.\n * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false.\n * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-exit', {\n tracker: event.eventSource,\n pointerType: event.pointerType,\n position: event.position,\n buttons: event.buttons,\n pointers: event.pointers,\n insideElementPressed: event.insideElementPressed,\n buttonDownAny: event.buttonDownAny,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onCanvasPress( event ) {\n /**\n * Raised when the primary mouse button is pressed or touch starts on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-press\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {String} pointerType - \"mouse\", \"touch\", \"pen\", etc.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false.\n * @property {Boolean} insideElementReleased - True if the cursor still inside the tracked element when the button was released.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-press', {\n tracker: event.eventSource,\n pointerType: event.pointerType,\n position: event.position,\n insideElementPressed: event.insideElementPressed,\n insideElementReleased: event.insideElementReleased,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onCanvasRelease( event ) {\n /**\n * Raised when the primary mouse button is released or touch ends on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-release\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {String} pointerType - \"mouse\", \"touch\", \"pen\", etc.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false.\n * @property {Boolean} insideElementReleased - True if the cursor still inside the tracked element when the button was released.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-release', {\n tracker: event.eventSource,\n pointerType: event.pointerType,\n position: event.position,\n insideElementPressed: event.insideElementPressed,\n insideElementReleased: event.insideElementReleased,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onCanvasNonPrimaryPress( event ) {\n /**\n * Raised when any non-primary pointer button is pressed on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-nonprimary-press\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {String} pointerType - \"mouse\", \"touch\", \"pen\", etc.\n * @property {Number} button - Button which caused the event.\n * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.\n * @property {Number} buttons - Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-nonprimary-press', {\n tracker: event.eventSource,\n position: event.position,\n pointerType: event.pointerType,\n button: event.button,\n buttons: event.buttons,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onCanvasNonPrimaryRelease( event ) {\n /**\n * Raised when any non-primary pointer button is released on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-nonprimary-release\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {String} pointerType - \"mouse\", \"touch\", \"pen\", etc.\n * @property {Number} button - Button which caused the event.\n * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.\n * @property {Number} buttons - Current buttons pressed.\n * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-nonprimary-release', {\n tracker: event.eventSource,\n position: event.position,\n pointerType: event.pointerType,\n button: event.button,\n buttons: event.buttons,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onCanvasPinch( event ) {\n var gestureSettings,\n centerPt,\n lastCenterPt,\n panByPt;\n\n if ( !event.preventDefaultAction && this.viewport ) {\n gestureSettings = this.gestureSettingsByDeviceType( event.pointerType );\n if ( gestureSettings.pinchToZoom ) {\n centerPt = this.viewport.pointFromPixel( event.center, true );\n lastCenterPt = this.viewport.pointFromPixel( event.lastCenter, true );\n panByPt = lastCenterPt.minus( centerPt );\n if( !this.panHorizontal ) {\n panByPt.x = 0;\n }\n if( !this.panVertical ) {\n panByPt.y = 0;\n }\n this.viewport.zoomBy( event.distance / event.lastDistance, centerPt, true );\n this.viewport.panBy( panByPt, true );\n this.viewport.applyConstraints();\n }\n if ( gestureSettings.pinchRotate ) {\n // Pinch rotate\n var angle1 = Math.atan2(event.gesturePoints[0].currentPos.y - event.gesturePoints[1].currentPos.y,\n event.gesturePoints[0].currentPos.x - event.gesturePoints[1].currentPos.x);\n var angle2 = Math.atan2(event.gesturePoints[0].lastPos.y - event.gesturePoints[1].lastPos.y,\n event.gesturePoints[0].lastPos.x - event.gesturePoints[1].lastPos.x);\n this.viewport.setRotation(this.viewport.getRotation() + ((angle1 - angle2) * (180 / Math.PI)));\n }\n }\n /**\n * Raised when a pinch event occurs on the {@link OpenSeadragon.Viewer#canvas} element.\n *\n * @event canvas-pinch\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {Array.} gesturePoints - Gesture points associated with the gesture. Velocity data can be found here.\n * @property {OpenSeadragon.Point} lastCenter - The previous center point of the two pinch contact points relative to the tracked element.\n * @property {OpenSeadragon.Point} center - The center point of the two pinch contact points relative to the tracked element.\n * @property {Number} lastDistance - The previous distance between the two pinch contact points in CSS pixels.\n * @property {Number} distance - The distance between the two pinch contact points in CSS pixels.\n * @property {Boolean} shift - True if the shift key was pressed during this event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent('canvas-pinch', {\n tracker: event.eventSource,\n gesturePoints: event.gesturePoints,\n lastCenter: event.lastCenter,\n center: event.center,\n lastDistance: event.lastDistance,\n distance: event.distance,\n shift: event.shift,\n originalEvent: event.originalEvent\n });\n //cancels event\n return false;\n}\n\nfunction onCanvasScroll( event ) {\n var gestureSettings,\n factor,\n thisScrollTime,\n deltaScrollTime;\n\n /* Certain scroll devices fire the scroll event way too fast so we are injecting a simple adjustment to keep things\n * partially normalized. If we have already fired an event within the last 'minScrollDelta' milliseconds we skip\n * this one and wait for the next event. */\n thisScrollTime = $.now();\n deltaScrollTime = thisScrollTime - this._lastScrollTime;\n if (deltaScrollTime > this.minScrollDeltaTime) {\n this._lastScrollTime = thisScrollTime;\n\n if ( !event.preventDefaultAction && this.viewport ) {\n gestureSettings = this.gestureSettingsByDeviceType( event.pointerType );\n if ( gestureSettings.scrollToZoom ) {\n factor = Math.pow( this.zoomPerScroll, event.scroll );\n this.viewport.zoomBy(\n factor,\n this.viewport.pointFromPixel( event.position, true )\n );\n this.viewport.applyConstraints();\n }\n }\n /**\n * Raised when a scroll event occurs on the {@link OpenSeadragon.Viewer#canvas} element (mouse wheel).\n *\n * @event canvas-scroll\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Number} scroll - The scroll delta for the event.\n * @property {Boolean} shift - True if the shift key was pressed during this event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'canvas-scroll', {\n tracker: event.eventSource,\n position: event.position,\n scroll: event.scroll,\n shift: event.shift,\n originalEvent: event.originalEvent\n });\n if (gestureSettings && gestureSettings.scrollToZoom) {\n //cancels event\n return false;\n }\n }\n else {\n gestureSettings = this.gestureSettingsByDeviceType( event.pointerType );\n if (gestureSettings && gestureSettings.scrollToZoom) {\n return false; // We are swallowing this event\n }\n }\n}\n\nfunction onContainerEnter( event ) {\n THIS[ this.hash ].mouseInside = true;\n abortControlsAutoHide( this );\n /**\n * Raised when the cursor enters the {@link OpenSeadragon.Viewer#container} element.\n *\n * @event container-enter\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @property {Number} pointers - Number of pointers (all types) active in the tracked element.\n * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false.\n * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'container-enter', {\n tracker: event.eventSource,\n position: event.position,\n buttons: event.buttons,\n pointers: event.pointers,\n insideElementPressed: event.insideElementPressed,\n buttonDownAny: event.buttonDownAny,\n originalEvent: event.originalEvent\n });\n}\n\nfunction onContainerExit( event ) {\n if ( event.pointers < 1 ) {\n THIS[ this.hash ].mouseInside = false;\n if ( !THIS[ this.hash ].animating ) {\n beginControlsAutoHide( this );\n }\n }\n /**\n * Raised when the cursor leaves the {@link OpenSeadragon.Viewer#container} element.\n *\n * @event container-exit\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.\n * @property {Number} pointers - Number of pointers (all types) active in the tracked element.\n * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false.\n * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'container-exit', {\n tracker: event.eventSource,\n position: event.position,\n buttons: event.buttons,\n pointers: event.pointers,\n insideElementPressed: event.insideElementPressed,\n buttonDownAny: event.buttonDownAny,\n originalEvent: event.originalEvent\n });\n}\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Page update routines ( aka Views - for future reference )\n///////////////////////////////////////////////////////////////////////////////\n\nfunction updateMulti( viewer ) {\n updateOnce( viewer );\n\n // Request the next frame, unless we've been closed\n if ( viewer.isOpen() ) {\n viewer._updateRequestId = scheduleUpdate( viewer, updateMulti );\n } else {\n viewer._updateRequestId = false;\n }\n}\n\nfunction updateOnce( viewer ) {\n\n //viewer.profiler.beginUpdate();\n\n if (viewer._opening) {\n return;\n }\n\n if (viewer.autoResize) {\n var containerSize = _getSafeElemSize(viewer.container);\n var prevContainerSize = THIS[viewer.hash].prevContainerSize;\n if (!containerSize.equals(prevContainerSize)) {\n var viewport = viewer.viewport;\n if (viewer.preserveImageSizeOnResize) {\n var resizeRatio = prevContainerSize.x / containerSize.x;\n var zoom = viewport.getZoom() * resizeRatio;\n var center = viewport.getCenter();\n viewport.resize(containerSize, false);\n viewport.zoomTo(zoom, null, true);\n viewport.panTo(center, true);\n } else {\n // maintain image position\n var oldBounds = viewport.getBounds();\n viewport.resize(containerSize, true);\n viewport.fitBoundsWithConstraints(oldBounds, true);\n }\n THIS[viewer.hash].prevContainerSize = containerSize;\n THIS[viewer.hash].forceRedraw = true;\n }\n }\n\n var viewportChange = viewer.viewport.update();\n var animated = viewer.world.update() || viewportChange;\n\n if (viewportChange) {\n /**\n * Raised when any spring animation update occurs (zoom, pan, etc.),\n * before the viewer has drawn the new location.\n *\n * @event viewport-change\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n viewer.raiseEvent('viewport-change');\n }\n\n if( viewer.referenceStrip ){\n animated = viewer.referenceStrip.update( viewer.viewport ) || animated;\n }\n\n if ( !THIS[ viewer.hash ].animating && animated ) {\n /**\n * Raised when any spring animation starts (zoom, pan, etc.).\n *\n * @event animation-start\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n viewer.raiseEvent( \"animation-start\" );\n abortControlsAutoHide( viewer );\n }\n\n if ( animated || THIS[ viewer.hash ].forceRedraw || viewer.world.needsDraw() ) {\n drawWorld( viewer );\n viewer._drawOverlays();\n if( viewer.navigator ){\n viewer.navigator.update( viewer.viewport );\n }\n\n THIS[ viewer.hash ].forceRedraw = false;\n\n if (animated) {\n /**\n * Raised when any spring animation update occurs (zoom, pan, etc.),\n * after the viewer has drawn the new location.\n *\n * @event animation\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n viewer.raiseEvent( \"animation\" );\n }\n }\n\n if ( THIS[ viewer.hash ].animating && !animated ) {\n /**\n * Raised when any spring animation ends (zoom, pan, etc.).\n *\n * @event animation-finish\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n viewer.raiseEvent( \"animation-finish\" );\n\n if ( !THIS[ viewer.hash ].mouseInside ) {\n beginControlsAutoHide( viewer );\n }\n }\n\n THIS[ viewer.hash ].animating = animated;\n\n //viewer.profiler.endUpdate();\n}\n\nfunction drawWorld( viewer ) {\n viewer.imageLoader.clear();\n viewer.drawer.clear();\n viewer.world.draw();\n\n /**\n * - Needs documentation -\n *\n * @event update-viewport\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n viewer.raiseEvent( 'update-viewport', {} );\n}\n\n///////////////////////////////////////////////////////////////////////////////\n// Navigation Controls\n///////////////////////////////////////////////////////////////////////////////\nfunction resolveUrl( prefix, url ) {\n return prefix ? prefix + url : url;\n}\n\n\n\nfunction beginZoomingIn() {\n THIS[ this.hash ].lastZoomTime = $.now();\n THIS[ this.hash ].zoomFactor = this.zoomPerSecond;\n THIS[ this.hash ].zooming = true;\n scheduleZoom( this );\n}\n\n\nfunction beginZoomingOut() {\n THIS[ this.hash ].lastZoomTime = $.now();\n THIS[ this.hash ].zoomFactor = 1.0 / this.zoomPerSecond;\n THIS[ this.hash ].zooming = true;\n scheduleZoom( this );\n}\n\n\nfunction endZooming() {\n THIS[ this.hash ].zooming = false;\n}\n\n\nfunction scheduleZoom( viewer ) {\n $.requestAnimationFrame( $.delegate( viewer, doZoom ) );\n}\n\n\nfunction doZoom() {\n var currentTime,\n deltaTime,\n adjustedFactor;\n\n if ( THIS[ this.hash ].zooming && this.viewport) {\n currentTime = $.now();\n deltaTime = currentTime - THIS[ this.hash ].lastZoomTime;\n adjustedFactor = Math.pow( THIS[ this.hash ].zoomFactor, deltaTime / 1000 );\n\n this.viewport.zoomBy( adjustedFactor );\n this.viewport.applyConstraints();\n THIS[ this.hash ].lastZoomTime = currentTime;\n scheduleZoom( this );\n }\n}\n\n\nfunction doSingleZoomIn() {\n if ( this.viewport ) {\n THIS[ this.hash ].zooming = false;\n this.viewport.zoomBy(\n this.zoomPerClick / 1.0\n );\n this.viewport.applyConstraints();\n }\n}\n\n\nfunction doSingleZoomOut() {\n if ( this.viewport ) {\n THIS[ this.hash ].zooming = false;\n this.viewport.zoomBy(\n 1.0 / this.zoomPerClick\n );\n this.viewport.applyConstraints();\n }\n}\n\n\nfunction lightUp() {\n this.buttons.emulateEnter();\n this.buttons.emulateExit();\n}\n\n\nfunction onHome() {\n if ( this.viewport ) {\n this.viewport.goHome();\n }\n}\n\n\nfunction onFullScreen() {\n if ( this.isFullPage() && !$.isFullScreen() ) {\n // Is fullPage but not fullScreen\n this.setFullPage( false );\n } else {\n this.setFullScreen( !this.isFullPage() );\n }\n // correct for no mouseout event on change\n if ( this.buttons ) {\n this.buttons.emulateExit();\n }\n this.fullPageButton.element.focus();\n if ( this.viewport ) {\n this.viewport.applyConstraints();\n }\n}\n\n/**\n * Note: The current rotation feature is limited to 90 degree turns.\n */\nfunction onRotateLeft() {\n if ( this.viewport ) {\n var currRotation = this.viewport.getRotation();\n if (currRotation === 0) {\n currRotation = 270;\n }\n else {\n currRotation -= 90;\n }\n this.viewport.setRotation(currRotation);\n }\n}\n\n/**\n * Note: The current rotation feature is limited to 90 degree turns.\n */\nfunction onRotateRight() {\n if ( this.viewport ) {\n var currRotation = this.viewport.getRotation();\n if (currRotation === 270) {\n currRotation = 0;\n }\n else {\n currRotation += 90;\n }\n this.viewport.setRotation(currRotation);\n }\n}\n\n\nfunction onPrevious(){\n var previous = this._sequenceIndex - 1;\n if(this.navPrevNextWrap && previous < 0){\n previous += this.tileSources.length;\n }\n this.goToPage( previous );\n}\n\n\nfunction onNext(){\n var next = this._sequenceIndex + 1;\n if(this.navPrevNextWrap && next >= this.tileSources.length){\n next = 0;\n }\n this.goToPage( next );\n}\n\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - Navigator\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class Navigator\n * @classdesc The Navigator provides a small view of the current image as fixed\n * while representing the viewport as a moving box serving as a frame\n * of reference in the larger viewport as to which portion of the image\n * is currently being examined. The navigator's viewport can be interacted\n * with using the keyboard or the mouse.\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.Viewer\n * @extends OpenSeadragon.EventSource\n * @param {Object} options\n */\n$.Navigator = function( options ){\n\n var viewer = options.viewer,\n _this = this,\n viewerSize,\n navigatorSize;\n\n //We may need to create a new element and id if they did not\n //provide the id for the existing element\n if( !options.id ){\n options.id = 'navigator-' + $.now();\n this.element = $.makeNeutralElement( \"div\" );\n options.controlOptions = {\n anchor: $.ControlAnchor.TOP_RIGHT,\n attachToViewer: true,\n autoFade: options.autoFade\n };\n\n if( options.position ){\n if( 'BOTTOM_RIGHT' == options.position ){\n options.controlOptions.anchor = $.ControlAnchor.BOTTOM_RIGHT;\n } else if( 'BOTTOM_LEFT' == options.position ){\n options.controlOptions.anchor = $.ControlAnchor.BOTTOM_LEFT;\n } else if( 'TOP_RIGHT' == options.position ){\n options.controlOptions.anchor = $.ControlAnchor.TOP_RIGHT;\n } else if( 'TOP_LEFT' == options.position ){\n options.controlOptions.anchor = $.ControlAnchor.TOP_LEFT;\n } else if( 'ABSOLUTE' == options.position ){\n options.controlOptions.anchor = $.ControlAnchor.ABSOLUTE;\n options.controlOptions.top = options.top;\n options.controlOptions.left = options.left;\n options.controlOptions.height = options.height;\n options.controlOptions.width = options.width;\n }\n }\n\n } else {\n this.element = document.getElementById( options.id );\n options.controlOptions = {\n anchor: $.ControlAnchor.NONE,\n attachToViewer: false,\n autoFade: false\n };\n }\n this.element.id = options.id;\n this.element.className += ' navigator';\n\n options = $.extend( true, {\n sizeRatio: $.DEFAULT_SETTINGS.navigatorSizeRatio\n }, options, {\n element: this.element,\n tabIndex: -1, // No keyboard navigation, omit from tab order\n //These need to be overridden to prevent recursion since\n //the navigator is a viewer and a viewer has a navigator\n showNavigator: false,\n mouseNavEnabled: false,\n showNavigationControl: false,\n showSequenceControl: false,\n immediateRender: true,\n blendTime: 0,\n animationTime: 0,\n autoResize: options.autoResize,\n // prevent resizing the navigator from adding unwanted space around the image\n minZoomImageRatio: 1.0\n });\n\n options.minPixelRatio = this.minPixelRatio = viewer.minPixelRatio;\n\n $.setElementTouchActionNone( this.element );\n\n this.borderWidth = 2;\n //At some browser magnification levels the display regions lines up correctly, but at some there appears to\n //be a one pixel gap.\n this.fudge = new $.Point(1, 1);\n this.totalBorderWidths = new $.Point(this.borderWidth * 2, this.borderWidth * 2).minus(this.fudge);\n\n\n if ( options.controlOptions.anchor != $.ControlAnchor.NONE ) {\n (function( style, borderWidth ){\n style.margin = '0px';\n style.border = borderWidth + 'px solid #555';\n style.padding = '0px';\n style.background = '#000';\n style.opacity = 0.8;\n style.overflow = 'hidden';\n }( this.element.style, this.borderWidth));\n }\n\n this.displayRegion = $.makeNeutralElement( \"div\" );\n this.displayRegion.id = this.element.id + '-displayregion';\n this.displayRegion.className = 'displayregion';\n\n (function( style, borderWidth ){\n style.position = 'relative';\n style.top = '0px';\n style.left = '0px';\n style.fontSize = '0px';\n style.overflow = 'hidden';\n style.border = borderWidth + 'px solid #900';\n style.margin = '0px';\n style.padding = '0px';\n //TODO: IE doesnt like this property being set\n //try{ style.outline = '2px auto #909'; }catch(e){/*ignore*/}\n\n style.background = 'transparent';\n\n // We use square bracket notation on the statement below, because float is a keyword.\n // This is important for the Google Closure compiler, if nothing else.\n /*jshint sub:true */\n style['float'] = 'left'; //Webkit\n\n style.cssFloat = 'left'; //Firefox\n style.styleFloat = 'left'; //IE\n style.zIndex = 999999999;\n style.cursor = 'default';\n }( this.displayRegion.style, this.borderWidth ));\n\n this.displayRegionContainer = $.makeNeutralElement(\"div\");\n this.displayRegionContainer.id = this.element.id + '-displayregioncontainer';\n this.displayRegionContainer.className = \"displayregioncontainer\";\n this.displayRegionContainer.style.width = \"100%\";\n this.displayRegionContainer.style.height = \"100%\";\n\n viewer.addControl(\n this.element,\n options.controlOptions\n );\n\n this._resizeWithViewer = options.controlOptions.anchor != $.ControlAnchor.ABSOLUTE &&\n options.controlOptions.anchor != $.ControlAnchor.NONE;\n\n if ( this._resizeWithViewer ) {\n if ( options.width && options.height ) {\n this.element.style.height = typeof (options.height) == \"number\" ? (options.height + 'px') : options.height;\n this.element.style.width = typeof (options.width) == \"number\" ? (options.width + 'px') : options.width;\n } else {\n viewerSize = $.getElementSize( viewer.element );\n this.element.style.height = Math.round( viewerSize.y * options.sizeRatio ) + 'px';\n this.element.style.width = Math.round( viewerSize.x * options.sizeRatio ) + 'px';\n this.oldViewerSize = viewerSize;\n }\n navigatorSize = $.getElementSize( this.element );\n this.elementArea = navigatorSize.x * navigatorSize.y;\n }\n\n this.oldContainerSize = new $.Point( 0, 0 );\n\n $.Viewer.apply( this, [ options ] );\n\n this.displayRegionContainer.appendChild(this.displayRegion);\n this.element.getElementsByTagName('div')[0].appendChild(this.displayRegionContainer);\n\n function rotate(degrees) {\n _setTransformRotate(_this.displayRegionContainer, degrees);\n _setTransformRotate(_this.displayRegion, -degrees);\n _this.viewport.setRotation(degrees);\n }\n if (options.navigatorRotate) {\n var degrees = options.viewer.viewport ?\n options.viewer.viewport.getRotation() :\n options.viewer.degrees || 0;\n rotate(degrees);\n options.viewer.addHandler(\"rotate\", function (args) {\n rotate(args.degrees);\n });\n }\n\n // Remove the base class' (Viewer's) innerTracker and replace it with our own\n this.innerTracker.destroy();\n this.innerTracker = new $.MouseTracker({\n element: this.element,\n dragHandler: $.delegate( this, onCanvasDrag ),\n clickHandler: $.delegate( this, onCanvasClick ),\n releaseHandler: $.delegate( this, onCanvasRelease ),\n scrollHandler: $.delegate( this, onCanvasScroll )\n });\n\n this.addHandler(\"reset-size\", function() {\n if (_this.viewport) {\n _this.viewport.goHome(true);\n }\n });\n\n viewer.world.addHandler(\"item-index-change\", function(event) {\n window.setTimeout(function(){\n var item = _this.world.getItemAt(event.previousIndex);\n _this.world.setItemIndex(item, event.newIndex);\n }, 1);\n });\n\n viewer.world.addHandler(\"remove-item\", function(event) {\n var theirItem = event.item;\n var myItem = _this._getMatchingItem(theirItem);\n if (myItem) {\n _this.world.removeItem(myItem);\n }\n });\n\n this.update(viewer.viewport);\n};\n\n$.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.Navigator.prototype */{\n\n /**\n * Used to notify the navigator when its size has changed.\n * Especially useful when {@link OpenSeadragon.Options}.navigatorAutoResize is set to false and the navigator is resizable.\n * @function\n */\n updateSize: function () {\n if ( this.viewport ) {\n var containerSize = new $.Point(\n (this.container.clientWidth === 0 ? 1 : this.container.clientWidth),\n (this.container.clientHeight === 0 ? 1 : this.container.clientHeight)\n );\n\n if ( !containerSize.equals( this.oldContainerSize ) ) {\n this.viewport.resize( containerSize, true );\n this.viewport.goHome(true);\n this.oldContainerSize = containerSize;\n this.drawer.clear();\n this.world.draw();\n }\n }\n },\n\n /**\n * Used to update the navigator minimap's viewport rectangle when a change in the viewer's viewport occurs.\n * @function\n * @param {OpenSeadragon.Viewport} The viewport this navigator is tracking.\n */\n update: function( viewport ) {\n\n var viewerSize,\n newWidth,\n newHeight,\n bounds,\n topleft,\n bottomright;\n\n viewerSize = $.getElementSize( this.viewer.element );\n if ( this._resizeWithViewer && viewerSize.x && viewerSize.y && !viewerSize.equals( this.oldViewerSize ) ) {\n this.oldViewerSize = viewerSize;\n\n if ( this.maintainSizeRatio || !this.elementArea) {\n newWidth = viewerSize.x * this.sizeRatio;\n newHeight = viewerSize.y * this.sizeRatio;\n } else {\n newWidth = Math.sqrt(this.elementArea * (viewerSize.x / viewerSize.y));\n newHeight = this.elementArea / newWidth;\n }\n\n this.element.style.width = Math.round( newWidth ) + 'px';\n this.element.style.height = Math.round( newHeight ) + 'px';\n\n if (!this.elementArea) {\n this.elementArea = newWidth * newHeight;\n }\n\n this.updateSize();\n }\n\n if (viewport && this.viewport) {\n bounds = viewport.getBoundsNoRotate(true);\n topleft = this.viewport.pixelFromPointNoRotate(bounds.getTopLeft(), false);\n bottomright = this.viewport.pixelFromPointNoRotate(bounds.getBottomRight(), false)\n .minus( this.totalBorderWidths );\n\n //update style for navigator-box\n var style = this.displayRegion.style;\n style.display = this.world.getItemCount() ? 'block' : 'none';\n\n style.top = Math.round( topleft.y ) + 'px';\n style.left = Math.round( topleft.x ) + 'px';\n\n var width = Math.abs( topleft.x - bottomright.x );\n var height = Math.abs( topleft.y - bottomright.y );\n // make sure width and height are non-negative so IE doesn't throw\n style.width = Math.round( Math.max( width, 0 ) ) + 'px';\n style.height = Math.round( Math.max( height, 0 ) ) + 'px';\n }\n\n },\n\n // overrides Viewer.addTiledImage\n addTiledImage: function(options) {\n var _this = this;\n\n var original = options.originalTiledImage;\n delete options.original;\n\n var optionsClone = $.extend({}, options, {\n success: function(event) {\n var myItem = event.item;\n myItem._originalForNavigator = original;\n _this._matchBounds(myItem, original, true);\n\n function matchBounds() {\n _this._matchBounds(myItem, original);\n }\n\n function matchOpacity() {\n _this._matchOpacity(myItem, original);\n }\n\n function matchCompositeOperation() {\n _this._matchCompositeOperation(myItem, original);\n }\n\n original.addHandler('bounds-change', matchBounds);\n original.addHandler('clip-change', matchBounds);\n original.addHandler('opacity-change', matchOpacity);\n original.addHandler('composite-operation-change', matchCompositeOperation);\n }\n });\n\n return $.Viewer.prototype.addTiledImage.apply(this, [optionsClone]);\n },\n\n // private\n _getMatchingItem: function(theirItem) {\n var count = this.world.getItemCount();\n var item;\n for (var i = 0; i < count; i++) {\n item = this.world.getItemAt(i);\n if (item._originalForNavigator === theirItem) {\n return item;\n }\n }\n\n return null;\n },\n\n // private\n _matchBounds: function(myItem, theirItem, immediately) {\n var bounds = theirItem.getBoundsNoRotate();\n myItem.setPosition(bounds.getTopLeft(), immediately);\n myItem.setWidth(bounds.width, immediately);\n myItem.setRotation(theirItem.getRotation(), immediately);\n myItem.setClip(theirItem.getClip());\n },\n\n // private\n _matchOpacity: function(myItem, theirItem) {\n myItem.setOpacity(theirItem.opacity);\n },\n\n // private\n _matchCompositeOperation: function(myItem, theirItem) {\n myItem.setCompositeOperation(theirItem.compositeOperation);\n }\n});\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onCanvasClick( event ) {\n if ( event.quick && this.viewer.viewport ) {\n this.viewer.viewport.panTo(this.viewport.pointFromPixel(event.position));\n this.viewer.viewport.applyConstraints();\n }\n}\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onCanvasDrag( event ) {\n if ( this.viewer.viewport ) {\n if( !this.panHorizontal ){\n event.delta.x = 0;\n }\n if( !this.panVertical ){\n event.delta.y = 0;\n }\n this.viewer.viewport.panBy(\n this.viewport.deltaPointsFromPixels(\n event.delta\n )\n );\n if( this.viewer.constrainDuringPan ){\n this.viewer.viewport.applyConstraints();\n }\n }\n}\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onCanvasRelease( event ) {\n if ( event.insideElementPressed && this.viewer.viewport ) {\n this.viewer.viewport.applyConstraints();\n }\n}\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onCanvasScroll( event ) {\n /**\n * Raised when a scroll event occurs on the {@link OpenSeadragon.Viewer#navigator} element (mouse wheel, touch pinch, etc.).\n *\n * @event navigator-scroll\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.\n * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.\n * @property {Number} scroll - The scroll delta for the event.\n * @property {Boolean} shift - True if the shift key was pressed during this event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.viewer.raiseEvent( 'navigator-scroll', {\n tracker: event.eventSource,\n position: event.position,\n scroll: event.scroll,\n shift: event.shift,\n originalEvent: event.originalEvent\n });\n\n //dont scroll the page up and down if the user is scrolling\n //in the navigator\n return false;\n}\n\n/**\n * @function\n * @private\n * @param {Object} element\n * @param {Number} degrees\n */\nfunction _setTransformRotate (element, degrees) {\n element.style.webkitTransform = \"rotate(\" + degrees + \"deg)\";\n element.style.mozTransform = \"rotate(\" + degrees + \"deg)\";\n element.style.msTransform = \"rotate(\" + degrees + \"deg)\";\n element.style.oTransform = \"rotate(\" + degrees + \"deg)\";\n element.style.transform = \"rotate(\" + degrees + \"deg)\";\n}\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - getString/setString\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n//TODO: I guess this is where the i18n needs to be reimplemented. I'll look\n// into existing patterns for i18n in javascript but i think that mimicking\n// pythons gettext might be a reasonable approach.\nvar I18N = {\n Errors: {\n Dzc: \"Sorry, we don't support Deep Zoom Collections!\",\n Dzi: \"Hmm, this doesn't appear to be a valid Deep Zoom Image.\",\n Xml: \"Hmm, this doesn't appear to be a valid Deep Zoom Image.\",\n ImageFormat: \"Sorry, we don't support {0}-based Deep Zoom Images.\",\n Security: \"It looks like a security restriction stopped us from \" +\n \"loading this Deep Zoom Image.\",\n Status: \"This space unintentionally left blank ({0} {1}).\",\n OpenFailed: \"Unable to open {0}: {1}\"\n },\n\n Tooltips: {\n FullPage: \"Toggle full page\",\n Home: \"Go home\",\n ZoomIn: \"Zoom in\",\n ZoomOut: \"Zoom out\",\n NextPage: \"Next page\",\n PreviousPage: \"Previous page\",\n RotateLeft: \"Rotate left\",\n RotateRight: \"Rotate right\"\n }\n};\n\n$.extend( $, /** @lends OpenSeadragon */{\n\n /**\n * @function\n * @param {String} property\n */\n getString: function( prop ) {\n\n var props = prop.split('.'),\n string = null,\n args = arguments,\n container = I18N,\n i;\n\n for (i = 0; i < props.length - 1; i++) {\n // in case not a subproperty\n container = container[ props[ i ] ] || {};\n }\n string = container[ props[ i ] ];\n\n if ( typeof( string ) != \"string\" ) {\n $.console.log( \"Untranslated source string:\", prop );\n string = \"\"; // FIXME: this breaks gettext()-style convention, which would return source\n }\n\n return string.replace(/\\{\\d+\\}/g, function(capture) {\n var i = parseInt( capture.match( /\\d+/ ), 10 ) + 1;\n return i < args.length ?\n args[ i ] :\n \"\";\n });\n },\n\n /**\n * @function\n * @param {String} property\n * @param {*} value\n */\n setString: function( prop, value ) {\n\n var props = prop.split('.'),\n container = I18N,\n i;\n\n for ( i = 0; i < props.length - 1; i++ ) {\n if ( !container[ props[ i ] ] ) {\n container[ props[ i ] ] = {};\n }\n container = container[ props[ i ] ];\n }\n\n container[ props[ i ] ] = value;\n }\n\n});\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - Point\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class Point\n * @classdesc A Point is really used as a 2-dimensional vector, equally useful for\n * representing a point on a plane, or the height and width of a plane\n * not requiring any other frame of reference.\n *\n * @memberof OpenSeadragon\n * @param {Number} [x] The vector component 'x'. Defaults to the origin at 0.\n * @param {Number} [y] The vector component 'y'. Defaults to the origin at 0.\n */\n$.Point = function( x, y ) {\n /**\n * The vector component 'x'.\n * @member {Number} x\n * @memberof OpenSeadragon.Point#\n */\n this.x = typeof ( x ) == \"number\" ? x : 0;\n /**\n * The vector component 'y'.\n * @member {Number} y\n * @memberof OpenSeadragon.Point#\n */\n this.y = typeof ( y ) == \"number\" ? y : 0;\n};\n\n/** @lends OpenSeadragon.Point.prototype */\n$.Point.prototype = {\n /**\n * @function\n * @returns {OpenSeadragon.Point} a duplicate of this Point\n */\n clone: function() {\n return new $.Point(this.x, this.y);\n },\n\n /**\n * Add another Point to this point and return a new Point.\n * @function\n * @param {OpenSeadragon.Point} point The point to add vector components.\n * @returns {OpenSeadragon.Point} A new point representing the sum of the\n * vector components\n */\n plus: function( point ) {\n return new $.Point(\n this.x + point.x,\n this.y + point.y\n );\n },\n\n /**\n * Substract another Point to this point and return a new Point.\n * @function\n * @param {OpenSeadragon.Point} point The point to substract vector components.\n * @returns {OpenSeadragon.Point} A new point representing the substraction of the\n * vector components\n */\n minus: function( point ) {\n return new $.Point(\n this.x - point.x,\n this.y - point.y\n );\n },\n\n /**\n * Multiply this point by a factor and return a new Point.\n * @function\n * @param {Number} factor The factor to multiply vector components.\n * @returns {OpenSeadragon.Point} A new point representing the multiplication\n * of the vector components by the factor\n */\n times: function( factor ) {\n return new $.Point(\n this.x * factor,\n this.y * factor\n );\n },\n\n /**\n * Divide this point by a factor and return a new Point.\n * @function\n * @param {Number} factor The factor to divide vector components.\n * @returns {OpenSeadragon.Point} A new point representing the division of the\n * vector components by the factor\n */\n divide: function( factor ) {\n return new $.Point(\n this.x / factor,\n this.y / factor\n );\n },\n\n /**\n * Compute the opposite of this point and return a new Point.\n * @function\n * @returns {OpenSeadragon.Point} A new point representing the opposite of the\n * vector components\n */\n negate: function() {\n return new $.Point( -this.x, -this.y );\n },\n\n /**\n * Compute the distance between this point and another point.\n * @function\n * @param {OpenSeadragon.Point} point The point to compute the distance with.\n * @returns {Number} The distance between the 2 points\n */\n distanceTo: function( point ) {\n return Math.sqrt(\n Math.pow( this.x - point.x, 2 ) +\n Math.pow( this.y - point.y, 2 )\n );\n },\n\n /**\n * Compute the squared distance between this point and another point.\n * Useful for optimizing things like comparing distances.\n * @function\n * @param {OpenSeadragon.Point} point The point to compute the squared distance with.\n * @returns {Number} The squared distance between the 2 points\n */\n squaredDistanceTo: function( point ) {\n return Math.pow( this.x - point.x, 2 ) +\n Math.pow( this.y - point.y, 2 );\n },\n\n /**\n * Apply a function to each coordinate of this point and return a new point.\n * @function\n * @param {function} func The function to apply to each coordinate.\n * @returns {OpenSeadragon.Point} A new point with the coordinates computed\n * by the specified function\n */\n apply: function( func ) {\n return new $.Point( func( this.x ), func( this.y ) );\n },\n\n /**\n * Check if this point is equal to another one.\n * @function\n * @param {OpenSeadragon.Point} point The point to compare this point with.\n * @returns {Boolean} true if they are equal, false otherwise.\n */\n equals: function( point ) {\n return (\n point instanceof $.Point\n ) && (\n this.x === point.x\n ) && (\n this.y === point.y\n );\n },\n\n /**\n * Rotates the point around the specified pivot\n * From http://stackoverflow.com/questions/4465931/rotate-rectangle-around-a-point\n * @function\n * @param {Number} degress to rotate around the pivot.\n * @param {OpenSeadragon.Point} [pivot=(0,0)] Point around which to rotate.\n * Defaults to the origin.\n * @returns {OpenSeadragon.Point}. A new point representing the point rotated around the specified pivot\n */\n rotate: function (degrees, pivot) {\n pivot = pivot || new $.Point(0, 0);\n var cos;\n var sin;\n // Avoid float computations when possible\n if (degrees % 90 === 0) {\n var d = $.positiveModulo(degrees, 360);\n switch (d) {\n case 0:\n cos = 1;\n sin = 0;\n break;\n case 90:\n cos = 0;\n sin = 1;\n break;\n case 180:\n cos = -1;\n sin = 0;\n break;\n case 270:\n cos = 0;\n sin = -1;\n break;\n }\n } else {\n var angle = degrees * Math.PI / 180.0;\n cos = Math.cos(angle);\n sin = Math.sin(angle);\n }\n var x = cos * (this.x - pivot.x) - sin * (this.y - pivot.y) + pivot.x;\n var y = sin * (this.x - pivot.x) + cos * (this.y - pivot.y) + pivot.y;\n return new $.Point(x, y);\n },\n\n /**\n * Convert this point to a string in the format (x,y) where x and y are\n * rounded to the nearest integer.\n * @function\n * @returns {String} A string representation of this point.\n */\n toString: function() {\n return \"(\" + (Math.round(this.x * 100) / 100) + \",\" + (Math.round(this.y * 100) / 100) + \")\";\n }\n};\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - TileSource\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n\n/**\n * @class TileSource\n * @classdesc The TileSource contains the most basic implementation required to create a\n * smooth transition between layers in an image pyramid. It has only a single key\n * interface that must be implemented to complete its key functionality:\n * 'getTileUrl'. It also has several optional interfaces that can be\n * implemented if a new TileSource wishes to support configuration via a simple\n * object or array ('configure') and if the tile source supports or requires\n * configuration via retrieval of a document on the network ala AJAX or JSONP,\n * ('getImageInfo').\n *
      \n * By default the image pyramid is split into N layers where the image's longest\n * side in M (in pixels), where N is the smallest integer which satisfies\n * 2^(N+1) >= M.\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.EventSource\n * @param {Object} options\n * You can either specify a URL, or literally define the TileSource (by specifying\n * width, height, tileSize, tileOverlap, minLevel, and maxLevel). For the former,\n * the extending class is expected to implement 'getImageInfo' and 'configure'.\n * For the latter, the construction is assumed to occur through\n * the extending classes implementation of 'configure'.\n * @param {String} [options.url]\n * The URL for the data necessary for this TileSource.\n * @param {String} [options.referenceStripThumbnailUrl]\n * The URL for a thumbnail image to be used by the reference strip\n * @param {Function} [options.success]\n * A function to be called upon successful creation.\n * @param {Boolean} [options.ajaxWithCredentials]\n * If this TileSource needs to make an AJAX call, this specifies whether to set\n * the XHR's withCredentials (for accessing secure data).\n * @param {Object} [options.ajaxHeaders]\n * A set of headers to include in AJAX requests.\n * @param {Number} [options.width]\n * Width of the source image at max resolution in pixels.\n * @param {Number} [options.height]\n * Height of the source image at max resolution in pixels.\n * @param {Number} [options.tileSize]\n * The size of the tiles to assumed to make up each pyramid layer in pixels.\n * Tile size determines the point at which the image pyramid must be\n * divided into a matrix of smaller images.\n * Use options.tileWidth and options.tileHeight to support non-square tiles.\n * @param {Number} [options.tileWidth]\n * The width of the tiles to assumed to make up each pyramid layer in pixels.\n * @param {Number} [options.tileHeight]\n * The height of the tiles to assumed to make up each pyramid layer in pixels.\n * @param {Number} [options.tileOverlap]\n * The number of pixels each tile is expected to overlap touching tiles.\n * @param {Number} [options.minLevel]\n * The minimum level to attempt to load.\n * @param {Number} [options.maxLevel]\n * The maximum level to attempt to load.\n */\n$.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLevel ) {\n var _this = this;\n\n var args = arguments,\n options,\n i;\n\n if( $.isPlainObject( width ) ){\n options = width;\n }else{\n options = {\n width: args[0],\n height: args[1],\n tileSize: args[2],\n tileOverlap: args[3],\n minLevel: args[4],\n maxLevel: args[5]\n };\n }\n\n //Tile sources supply some events, namely 'ready' when they must be configured\n //by asynchronously fetching their configuration data.\n $.EventSource.call( this );\n\n //we allow options to override anything we dont treat as\n //required via idiomatic options or which is functionally\n //set depending on the state of the readiness of this tile\n //source\n $.extend( true, this, options );\n\n if (!this.success) {\n //Any functions that are passed as arguments are bound to the ready callback\n for ( i = 0; i < arguments.length; i++ ) {\n if ( $.isFunction( arguments[ i ] ) ) {\n this.success = arguments[ i ];\n //only one callback per constructor\n break;\n }\n }\n }\n\n if (this.success) {\n this.addHandler( 'ready', function ( event ) {\n _this.success( event );\n } );\n }\n\n /**\n * Ratio of width to height\n * @member {Number} aspectRatio\n * @memberof OpenSeadragon.TileSource#\n */\n /**\n * Vector storing x and y dimensions ( width and height respectively ).\n * @member {OpenSeadragon.Point} dimensions\n * @memberof OpenSeadragon.TileSource#\n */\n /**\n * The overlap in pixels each tile shares with its adjacent neighbors.\n * @member {Number} tileOverlap\n * @memberof OpenSeadragon.TileSource#\n */\n /**\n * The minimum pyramid level this tile source supports or should attempt to load.\n * @member {Number} minLevel\n * @memberof OpenSeadragon.TileSource#\n */\n /**\n * The maximum pyramid level this tile source supports or should attempt to load.\n * @member {Number} maxLevel\n * @memberof OpenSeadragon.TileSource#\n */\n /**\n *\n * @member {Boolean} ready\n * @memberof OpenSeadragon.TileSource#\n */\n\n if( 'string' == $.type( arguments[ 0 ] ) ){\n this.url = arguments[0];\n }\n\n if (this.url) {\n //in case the getImageInfo method is overriden and/or implies an\n //async mechanism set some safe defaults first\n this.aspectRatio = 1;\n this.dimensions = new $.Point( 10, 10 );\n this._tileWidth = 0;\n this._tileHeight = 0;\n this.tileOverlap = 0;\n this.minLevel = 0;\n this.maxLevel = 0;\n this.ready = false;\n //configuration via url implies the extending class\n //implements and 'configure'\n this.getImageInfo( this.url );\n\n } else {\n\n //explicit configuration via positional args in constructor\n //or the more idiomatic 'options' object\n this.ready = true;\n this.aspectRatio = (options.width && options.height) ?\n (options.width / options.height) : 1;\n this.dimensions = new $.Point( options.width, options.height );\n\n if ( this.tileSize ){\n this._tileWidth = this._tileHeight = this.tileSize;\n delete this.tileSize;\n } else {\n if( this.tileWidth ){\n // We were passed tileWidth in options, but we want to rename it\n // with a leading underscore to make clear that it is not safe to directly modify it\n this._tileWidth = this.tileWidth;\n delete this.tileWidth;\n } else {\n this._tileWidth = 0;\n }\n\n if( this.tileHeight ){\n // See note above about renaming this.tileWidth\n this._tileHeight = this.tileHeight;\n delete this.tileHeight;\n } else {\n this._tileHeight = 0;\n }\n }\n\n this.tileOverlap = options.tileOverlap ? options.tileOverlap : 0;\n this.minLevel = options.minLevel ? options.minLevel : 0;\n this.maxLevel = ( undefined !== options.maxLevel && null !== options.maxLevel ) ?\n options.maxLevel : (\n ( options.width && options.height ) ? Math.ceil(\n Math.log( Math.max( options.width, options.height ) ) /\n Math.log( 2 )\n ) : 0\n );\n if( this.success && $.isFunction( this.success ) ){\n this.success( this );\n }\n }\n\n\n};\n\n/** @lends OpenSeadragon.TileSource.prototype */\n$.TileSource.prototype = {\n\n getTileSize: function( level ) {\n $.console.error(\n \"[TileSource.getTileSize] is deprecated.\" +\n \"Use TileSource.getTileWidth() and TileSource.getTileHeight() instead\"\n );\n return this._tileWidth;\n },\n\n /**\n * Return the tileWidth for a given level.\n * Subclasses should override this if tileWidth can be different at different levels\n * such as in IIIFTileSource. Code should use this function rather than reading\n * from ._tileWidth directly.\n * @function\n * @param {Number} level\n */\n getTileWidth: function( level ) {\n if (!this._tileWidth) {\n return this.getTileSize(level);\n }\n return this._tileWidth;\n },\n\n /**\n * Return the tileHeight for a given level.\n * Subclasses should override this if tileHeight can be different at different levels\n * such as in IIIFTileSource. Code should use this function rather than reading\n * from ._tileHeight directly.\n * @function\n * @param {Number} level\n */\n getTileHeight: function( level ) {\n if (!this._tileHeight) {\n return this.getTileSize(level);\n }\n return this._tileHeight;\n },\n\n /**\n * @function\n * @param {Number} level\n */\n getLevelScale: function( level ) {\n\n // see https://github.com/openseadragon/openseadragon/issues/22\n // we use the tilesources implementation of getLevelScale to generate\n // a memoized re-implementation\n var levelScaleCache = {},\n i;\n for( i = 0; i <= this.maxLevel; i++ ){\n levelScaleCache[ i ] = 1 / Math.pow(2, this.maxLevel - i);\n }\n this.getLevelScale = function( _level ){\n return levelScaleCache[ _level ];\n };\n return this.getLevelScale( level );\n },\n\n /**\n * @function\n * @param {Number} level\n */\n getNumTiles: function( level ) {\n var scale = this.getLevelScale( level ),\n x = Math.ceil( scale * this.dimensions.x / this.getTileWidth(level) ),\n y = Math.ceil( scale * this.dimensions.y / this.getTileHeight(level) );\n\n return new $.Point( x, y );\n },\n\n /**\n * @function\n * @param {Number} level\n */\n getPixelRatio: function( level ) {\n var imageSizeScaled = this.dimensions.times( this.getLevelScale( level ) ),\n rx = 1.0 / imageSizeScaled.x,\n ry = 1.0 / imageSizeScaled.y;\n\n return new $.Point(rx, ry);\n },\n\n\n /**\n * @function\n * @returns {Number} The highest level in this tile source that can be contained in a single tile.\n */\n getClosestLevel: function() {\n var i,\n tiles;\n\n for (i = this.minLevel + 1; i <= this.maxLevel; i++){\n tiles = this.getNumTiles(i);\n if (tiles.x > 1 || tiles.y > 1) {\n break;\n }\n }\n\n return i - 1;\n },\n\n /**\n * @function\n * @param {Number} level\n * @param {OpenSeadragon.Point} point\n */\n getTileAtPoint: function(level, point) {\n var validPoint = point.x >= 0 && point.x <= 1 &&\n point.y >= 0 && point.y <= 1 / this.aspectRatio;\n $.console.assert(validPoint, \"[TileSource.getTileAtPoint] must be called with a valid point.\");\n\n var widthScaled = this.dimensions.x * this.getLevelScale(level);\n var pixelX = point.x * widthScaled;\n var pixelY = point.y * widthScaled;\n\n var x = Math.floor(pixelX / this.getTileWidth(level));\n var y = Math.floor(pixelY / this.getTileHeight(level));\n\n // When point.x == 1 or point.y == 1 / this.aspectRatio we want to\n // return the last tile of the row/column\n if (point.x >= 1) {\n x = this.getNumTiles(level).x - 1;\n }\n var EPSILON = 1e-16;\n if (point.y >= 1 / this.aspectRatio - EPSILON) {\n y = this.getNumTiles(level).y - 1;\n }\n\n return new $.Point(x, y);\n },\n\n /**\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n */\n getTileBounds: function( level, x, y ) {\n var dimensionsScaled = this.dimensions.times( this.getLevelScale( level ) ),\n tileWidth = this.getTileWidth(level),\n tileHeight = this.getTileHeight(level),\n px = ( x === 0 ) ? 0 : tileWidth * x - this.tileOverlap,\n py = ( y === 0 ) ? 0 : tileHeight * y - this.tileOverlap,\n sx = tileWidth + ( x === 0 ? 1 : 2 ) * this.tileOverlap,\n sy = tileHeight + ( y === 0 ? 1 : 2 ) * this.tileOverlap,\n scale = 1.0 / dimensionsScaled.x;\n\n sx = Math.min( sx, dimensionsScaled.x - px );\n sy = Math.min( sy, dimensionsScaled.y - py );\n\n return new $.Rect( px * scale, py * scale, sx * scale, sy * scale );\n },\n\n\n /**\n * Responsible for retrieving, and caching the\n * image metadata pertinent to this TileSources implementation.\n * @function\n * @param {String} url\n * @throws {Error}\n */\n getImageInfo: function( url ) {\n var _this = this,\n callbackName,\n callback,\n readySource,\n options,\n urlParts,\n filename,\n lastDot;\n\n\n if( url ) {\n urlParts = url.split( '/' );\n filename = urlParts[ urlParts.length - 1 ];\n lastDot = filename.lastIndexOf( '.' );\n if ( lastDot > -1 ) {\n urlParts[ urlParts.length - 1 ] = filename.slice( 0, lastDot );\n }\n }\n\n callback = function( data ){\n if( typeof(data) === \"string\" ) {\n data = $.parseXml( data );\n }\n var $TileSource = $.TileSource.determineType( _this, data, url );\n if ( !$TileSource ) {\n /**\n * Raised when an error occurs loading a TileSource.\n *\n * @event open-failed\n * @memberof OpenSeadragon.TileSource\n * @type {object}\n * @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event.\n * @property {String} message\n * @property {String} source\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( 'open-failed', { message: \"Unable to load TileSource\", source: url } );\n return;\n }\n\n options = $TileSource.prototype.configure.apply( _this, [ data, url ]);\n if (options.ajaxWithCredentials === undefined) {\n options.ajaxWithCredentials = _this.ajaxWithCredentials;\n }\n\n readySource = new $TileSource( options );\n _this.ready = true;\n /**\n * Raised when a TileSource is opened and initialized.\n *\n * @event ready\n * @memberof OpenSeadragon.TileSource\n * @type {object}\n * @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event.\n * @property {Object} tileSource\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( 'ready', { tileSource: readySource } );\n };\n\n if( url.match(/\\.js$/) ){\n //TODO: Its not very flexible to require tile sources to end jsonp\n // request for info with a url that ends with '.js' but for\n // now it's the only way I see to distinguish uniformly.\n callbackName = url.split('/').pop().replace('.js', '');\n $.jsonp({\n url: url,\n async: false,\n callbackName: callbackName,\n callback: callback\n });\n } else {\n // request info via xhr asynchronously.\n $.makeAjaxRequest( {\n url: url,\n withCredentials: this.ajaxWithCredentials,\n headers: this.ajaxHeaders,\n success: function( xhr ) {\n var data = processResponse( xhr );\n callback( data );\n },\n error: function ( xhr, exc ) {\n var msg;\n\n /*\n IE < 10 will block XHR requests to different origins. Any property access on the request\n object will raise an exception which we'll attempt to handle by formatting the original\n exception rather than the second one raised when we try to access xhr.status\n */\n try {\n msg = \"HTTP \" + xhr.status + \" attempting to load TileSource\";\n } catch ( e ) {\n var formattedExc;\n if ( typeof( exc ) == \"undefined\" || !exc.toString ) {\n formattedExc = \"Unknown error\";\n } else {\n formattedExc = exc.toString();\n }\n\n msg = formattedExc + \" attempting to load TileSource\";\n }\n\n /***\n * Raised when an error occurs loading a TileSource.\n *\n * @event open-failed\n * @memberof OpenSeadragon.TileSource\n * @type {object}\n * @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event.\n * @property {String} message\n * @property {String} source\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( 'open-failed', {\n message: msg,\n source: url\n });\n }\n });\n }\n\n },\n\n /**\n * Responsible determining if a the particular TileSource supports the\n * data format ( and allowed to apply logic against the url the data was\n * loaded from, if any ). Overriding implementations are expected to do\n * something smart with data and / or url to determine support. Also\n * understand that iteration order of TileSources is not guarunteed so\n * please make sure your data or url is expressive enough to ensure a simple\n * and sufficient mechanisim for clear determination.\n * @function\n * @param {String|Object|Array|Document} data\n * @param {String} url - the url the data was loaded\n * from if any.\n * @return {Boolean}\n */\n supports: function( data, url ) {\n return false;\n },\n\n /**\n * Responsible for parsing and configuring the\n * image metadata pertinent to this TileSources implementation.\n * This method is not implemented by this class other than to throw an Error\n * announcing you have to implement it. Because of the variety of tile\n * server technologies, and various specifications for building image\n * pyramids, this method is here to allow easy integration.\n * @function\n * @param {String|Object|Array|Document} data\n * @param {String} url - the url the data was loaded\n * from if any.\n * @return {Object} options - A dictionary of keyword arguments sufficient\n * to configure this tile sources constructor.\n * @throws {Error}\n */\n configure: function( data, url ) {\n throw new Error( \"Method not implemented.\" );\n },\n\n /**\n * Responsible for retrieving the url which will return an image for the\n * region specified by the given x, y, and level components.\n * This method is not implemented by this class other than to throw an Error\n * announcing you have to implement it. Because of the variety of tile\n * server technologies, and various specifications for building image\n * pyramids, this method is here to allow easy integration.\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n * @throws {Error}\n */\n getTileUrl: function( level, x, y ) {\n throw new Error( \"Method not implemented.\" );\n },\n\n /**\n * Responsible for retrieving the headers which will be attached to the image request for the\n * region specified by the given x, y, and level components.\n * This option is only relevant if {@link OpenSeadragon.Options}.loadTilesWithAjax is set to true.\n * The headers returned here will override headers specified at the Viewer or TiledImage level.\n * Specifying a falsy value for a header will clear its existing value set at the Viewer or\n * TiledImage level (if any).\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n * @returns {Object}\n */\n getTileAjaxHeaders: function( level, x, y ) {\n return {};\n },\n\n /**\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n */\n tileExists: function( level, x, y ) {\n var numTiles = this.getNumTiles( level );\n return level >= this.minLevel &&\n level <= this.maxLevel &&\n x >= 0 &&\n y >= 0 &&\n x < numTiles.x &&\n y < numTiles.y;\n }\n};\n\n\n$.extend( true, $.TileSource.prototype, $.EventSource.prototype );\n\n\n/**\n * Decides whether to try to process the response as xml, json, or hand back\n * the text\n * @private\n * @inner\n * @function\n * @param {XMLHttpRequest} xhr - the completed network request\n */\nfunction processResponse( xhr ){\n var responseText = xhr.responseText,\n status = xhr.status,\n statusText,\n data;\n\n if ( !xhr ) {\n throw new Error( $.getString( \"Errors.Security\" ) );\n } else if ( xhr.status !== 200 && xhr.status !== 0 ) {\n status = xhr.status;\n statusText = ( status == 404 ) ?\n \"Not Found\" :\n xhr.statusText;\n throw new Error( $.getString( \"Errors.Status\", status, statusText ) );\n }\n\n if( responseText.match(/\\s*<.*/) ){\n try{\n data = ( xhr.responseXML && xhr.responseXML.documentElement ) ?\n xhr.responseXML :\n $.parseXml( responseText );\n } catch (e){\n data = xhr.responseText;\n }\n }else if( responseText.match(/\\s*[\\{\\[].*/) ){\n try{\n data = $.parseJSON(responseText);\n } catch(e){\n data = responseText;\n }\n }else{\n data = responseText;\n }\n return data;\n}\n\n\n/**\n * Determines the TileSource Implementation by introspection of OpenSeadragon\n * namespace, calling each TileSource implementation of 'isType'\n * @private\n * @inner\n * @function\n * @param {Object|Array|Document} data - the tile source configuration object\n * @param {String} url - the url where the tile source configuration object was\n * loaded from, if any.\n */\n$.TileSource.determineType = function( tileSource, data, url ){\n var property;\n for( property in OpenSeadragon ){\n if( property.match(/.+TileSource$/) &&\n $.isFunction( OpenSeadragon[ property ] ) &&\n $.isFunction( OpenSeadragon[ property ].prototype.supports ) &&\n OpenSeadragon[ property ].prototype.supports.call( tileSource, data, url )\n ){\n return OpenSeadragon[ property ];\n }\n }\n\n $.console.error( \"No TileSource was able to open %s %s\", url, data );\n};\n\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - DziTileSource\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class DziTileSource\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.TileSource\n * @param {Number|Object} width - the pixel width of the image or the idiomatic\n * options object which is used instead of positional arguments.\n * @param {Number} height\n * @param {Number} tileSize\n * @param {Number} tileOverlap\n * @param {String} tilesUrl\n * @param {String} fileFormat\n * @param {OpenSeadragon.DisplayRect[]} displayRects\n * @property {String} tilesUrl\n * @property {String} fileFormat\n * @property {OpenSeadragon.DisplayRect[]} displayRects\n */\n$.DziTileSource = function( width, height, tileSize, tileOverlap, tilesUrl, fileFormat, displayRects, minLevel, maxLevel ) {\n var i,\n rect,\n level,\n options;\n\n if( $.isPlainObject( width ) ){\n options = width;\n }else{\n options = {\n width: arguments[ 0 ],\n height: arguments[ 1 ],\n tileSize: arguments[ 2 ],\n tileOverlap: arguments[ 3 ],\n tilesUrl: arguments[ 4 ],\n fileFormat: arguments[ 5 ],\n displayRects: arguments[ 6 ],\n minLevel: arguments[ 7 ],\n maxLevel: arguments[ 8 ]\n };\n }\n\n this._levelRects = {};\n this.tilesUrl = options.tilesUrl;\n this.fileFormat = options.fileFormat;\n this.displayRects = options.displayRects;\n\n if ( this.displayRects ) {\n for ( i = this.displayRects.length - 1; i >= 0; i-- ) {\n rect = this.displayRects[ i ];\n for ( level = rect.minLevel; level <= rect.maxLevel; level++ ) {\n if ( !this._levelRects[ level ] ) {\n this._levelRects[ level ] = [];\n }\n this._levelRects[ level ].push( rect );\n }\n }\n }\n\n $.TileSource.apply( this, [ options ] );\n\n};\n\n$.extend( $.DziTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.DziTileSource.prototype */{\n\n\n /**\n * Determine if the data and/or url imply the image service is supported by\n * this tile source.\n * @function\n * @param {Object|Array} data\n * @param {String} optional - url\n */\n supports: function( data, url ){\n var ns;\n if ( data.Image ) {\n ns = data.Image.xmlns;\n } else if ( data.documentElement) {\n if (\"Image\" == data.documentElement.localName || \"Image\" == data.documentElement.tagName) {\n ns = data.documentElement.namespaceURI;\n }\n }\n\n ns = (ns || '').toLowerCase();\n\n return (ns.indexOf('schemas.microsoft.com/deepzoom/2008') !== -1 ||\n ns.indexOf('schemas.microsoft.com/deepzoom/2009') !== -1);\n },\n\n /**\n *\n * @function\n * @param {Object|XMLDocument} data - the raw configuration\n * @param {String} url - the url the data was retreived from if any.\n * @return {Object} options - A dictionary of keyword arguments sufficient\n * to configure this tile sources constructor.\n */\n configure: function( data, url ){\n\n var options;\n\n if( !$.isPlainObject(data) ){\n\n options = configureFromXML( this, data );\n\n }else{\n\n options = configureFromObject( this, data );\n }\n\n if (url && !options.tilesUrl) {\n options.tilesUrl = url.replace(\n /([^\\/]+?)(\\.(dzi|xml|js)?(\\?[^\\/]*)?)?\\/?$/, '$1_files/');\n\n if (url.search(/\\.(dzi|xml|js)\\?/) != -1) {\n options.queryParams = url.match(/\\?.*/);\n }else{\n options.queryParams = '';\n }\n }\n\n return options;\n },\n\n\n /**\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n */\n getTileUrl: function( level, x, y ) {\n return [ this.tilesUrl, level, '/', x, '_', y, '.', this.fileFormat, this.queryParams ].join( '' );\n },\n\n\n /**\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n */\n tileExists: function( level, x, y ) {\n var rects = this._levelRects[ level ],\n rect,\n scale,\n xMin,\n yMin,\n xMax,\n yMax,\n i;\n\n if ( !rects || !rects.length ) {\n return true;\n }\n\n for ( i = rects.length - 1; i >= 0; i-- ) {\n rect = rects[ i ];\n\n if ( level < rect.minLevel || level > rect.maxLevel ) {\n continue;\n }\n\n scale = this.getLevelScale( level );\n xMin = rect.x * scale;\n yMin = rect.y * scale;\n xMax = xMin + rect.width * scale;\n yMax = yMin + rect.height * scale;\n\n xMin = Math.floor( xMin / this._tileWidth );\n yMin = Math.floor( yMin / this._tileWidth ); // DZI tiles are square, so we just use _tileWidth\n xMax = Math.ceil( xMax / this._tileWidth );\n yMax = Math.ceil( yMax / this._tileWidth );\n\n if ( xMin <= x && x < xMax && yMin <= y && y < yMax ) {\n return true;\n }\n }\n\n return false;\n }\n});\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction configureFromXML( tileSource, xmlDoc ){\n\n if ( !xmlDoc || !xmlDoc.documentElement ) {\n throw new Error( $.getString( \"Errors.Xml\" ) );\n }\n\n var root = xmlDoc.documentElement,\n rootName = root.localName || root.tagName,\n ns = xmlDoc.documentElement.namespaceURI,\n configuration = null,\n displayRects = [],\n dispRectNodes,\n dispRectNode,\n rectNode,\n sizeNode,\n i;\n\n if ( rootName == \"Image\" ) {\n\n try {\n sizeNode = root.getElementsByTagName(\"Size\" )[ 0 ];\n if (sizeNode === undefined) {\n sizeNode = root.getElementsByTagNameNS(ns, \"Size\" )[ 0 ];\n }\n\n configuration = {\n Image: {\n xmlns: \"http://schemas.microsoft.com/deepzoom/2008\",\n Url: root.getAttribute( \"Url\" ),\n Format: root.getAttribute( \"Format\" ),\n DisplayRect: null,\n Overlap: parseInt( root.getAttribute( \"Overlap\" ), 10 ),\n TileSize: parseInt( root.getAttribute( \"TileSize\" ), 10 ),\n Size: {\n Height: parseInt( sizeNode.getAttribute( \"Height\" ), 10 ),\n Width: parseInt( sizeNode.getAttribute( \"Width\" ), 10 )\n }\n }\n };\n\n if ( !$.imageFormatSupported( configuration.Image.Format ) ) {\n throw new Error(\n $.getString( \"Errors.ImageFormat\", configuration.Image.Format.toUpperCase() )\n );\n }\n\n dispRectNodes = root.getElementsByTagName(\"DisplayRect\" );\n if (dispRectNodes === undefined) {\n dispRectNodes = root.getElementsByTagNameNS(ns, \"DisplayRect\" )[ 0 ];\n }\n\n for ( i = 0; i < dispRectNodes.length; i++ ) {\n dispRectNode = dispRectNodes[ i ];\n rectNode = dispRectNode.getElementsByTagName(\"Rect\" )[ 0 ];\n if (rectNode === undefined) {\n rectNode = dispRectNode.getElementsByTagNameNS(ns, \"Rect\" )[ 0 ];\n }\n\n displayRects.push({\n Rect: {\n X: parseInt( rectNode.getAttribute( \"X\" ), 10 ),\n Y: parseInt( rectNode.getAttribute( \"Y\" ), 10 ),\n Width: parseInt( rectNode.getAttribute( \"Width\" ), 10 ),\n Height: parseInt( rectNode.getAttribute( \"Height\" ), 10 ),\n MinLevel: parseInt( dispRectNode.getAttribute( \"MinLevel\" ), 10 ),\n MaxLevel: parseInt( dispRectNode.getAttribute( \"MaxLevel\" ), 10 )\n }\n });\n }\n\n if( displayRects.length ){\n configuration.Image.DisplayRect = displayRects;\n }\n\n return configureFromObject( tileSource, configuration );\n\n } catch ( e ) {\n throw (e instanceof Error) ?\n e :\n new Error( $.getString(\"Errors.Dzi\") );\n }\n } else if ( rootName == \"Collection\" ) {\n throw new Error( $.getString( \"Errors.Dzc\" ) );\n } else if ( rootName == \"Error\" ) {\n var messageNode = root.getElementsByTagName(\"Message\")[0];\n var message = messageNode.firstChild.nodeValue;\n throw new Error(message);\n }\n\n throw new Error( $.getString( \"Errors.Dzi\" ) );\n}\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction configureFromObject( tileSource, configuration ){\n var imageData = configuration.Image,\n tilesUrl = imageData.Url,\n fileFormat = imageData.Format,\n sizeData = imageData.Size,\n dispRectData = imageData.DisplayRect || [],\n width = parseInt( sizeData.Width, 10 ),\n height = parseInt( sizeData.Height, 10 ),\n tileSize = parseInt( imageData.TileSize, 10 ),\n tileOverlap = parseInt( imageData.Overlap, 10 ),\n displayRects = [],\n rectData,\n i;\n\n //TODO: need to figure out out to better handle image format compatibility\n // which actually includes additional file formats like xml and pdf\n // and plain text for various tilesource implementations to avoid low\n // level errors.\n //\n // For now, just don't perform the check.\n //\n /*if ( !imageFormatSupported( fileFormat ) ) {\n throw new Error(\n $.getString( \"Errors.ImageFormat\", fileFormat.toUpperCase() )\n );\n }*/\n\n for ( i = 0; i < dispRectData.length; i++ ) {\n rectData = dispRectData[ i ].Rect;\n\n displayRects.push( new $.DisplayRect(\n parseInt( rectData.X, 10 ),\n parseInt( rectData.Y, 10 ),\n parseInt( rectData.Width, 10 ),\n parseInt( rectData.Height, 10 ),\n parseInt( rectData.MinLevel, 10 ),\n parseInt( rectData.MaxLevel, 10 )\n ));\n }\n\n return $.extend(true, {\n width: width, /* width *required */\n height: height, /* height *required */\n tileSize: tileSize, /* tileSize *required */\n tileOverlap: tileOverlap, /* tileOverlap *required */\n minLevel: null, /* minLevel */\n maxLevel: null, /* maxLevel */\n tilesUrl: tilesUrl, /* tilesUrl */\n fileFormat: fileFormat, /* fileFormat */\n displayRects: displayRects /* displayRects */\n }, configuration );\n\n}\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - IIIFTileSource\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class IIIFTileSource\n * @classdesc A client implementation of the International Image Interoperability Framework\n * Format: Image API 1.0 - 2.1\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.TileSource\n * @see http://iiif.io/api/image/\n */\n$.IIIFTileSource = function( options ){\n\n /* eslint-disable camelcase */\n\n $.extend( true, this, options );\n\n if ( !( this.height && this.width && this['@id'] ) ) {\n throw new Error( 'IIIF required parameters not provided.' );\n }\n\n options.tileSizePerScaleFactor = {};\n\n // N.B. 2.0 renamed scale_factors to scaleFactors\n if ( this.tile_width && this.tile_height ) {\n options.tileWidth = this.tile_width;\n options.tileHeight = this.tile_height;\n } else if ( this.tile_width ) {\n options.tileSize = this.tile_width;\n } else if ( this.tile_height ) {\n options.tileSize = this.tile_height;\n } else if ( this.tiles ) {\n // Version 2.0 forwards\n if ( this.tiles.length == 1 ) {\n options.tileWidth = this.tiles[0].width;\n // Use height if provided, otherwise assume square tiles and use width.\n options.tileHeight = this.tiles[0].height || this.tiles[0].width;\n this.scale_factors = this.tiles[0].scaleFactors;\n } else {\n // Multiple tile sizes at different levels\n this.scale_factors = [];\n for (var t = 0; t < this.tiles.length; t++ ) {\n for (var sf = 0; sf < this.tiles[t].scaleFactors.length; sf++) {\n var scaleFactor = this.tiles[t].scaleFactors[sf];\n this.scale_factors.push(scaleFactor);\n options.tileSizePerScaleFactor[scaleFactor] = {\n width: this.tiles[t].width,\n height: this.tiles[t].height || this.tiles[t].width\n };\n }\n }\n }\n } else if ( canBeTiled(options.profile) ) {\n // use the largest of tileOptions that is smaller than the short dimension\n var shortDim = Math.min( this.height, this.width ),\n tileOptions = [256, 512, 1024],\n smallerTiles = [];\n\n for ( var c = 0; c < tileOptions.length; c++ ) {\n if ( tileOptions[c] <= shortDim ) {\n smallerTiles.push( tileOptions[c] );\n }\n }\n\n if ( smallerTiles.length > 0 ) {\n options.tileSize = Math.max.apply( null, smallerTiles );\n } else {\n // If we're smaller than 256, just use the short side.\n options.tileSize = shortDim;\n }\n } else if (this.sizes && this.sizes.length > 0) {\n // This info.json can't be tiled, but we can still construct a legacy pyramid from the sizes array.\n // In this mode, IIIFTileSource will call functions from the abstract baseTileSource or the\n // LegacyTileSource instead of performing IIIF tiling.\n this.emulateLegacyImagePyramid = true;\n\n options.levels = constructLevels( this );\n // use the largest available size to define tiles\n $.extend( true, options, {\n width: options.levels[ options.levels.length - 1 ].width,\n height: options.levels[ options.levels.length - 1 ].height,\n tileSize: Math.max( options.height, options.width ),\n tileOverlap: 0,\n minLevel: 0,\n maxLevel: options.levels.length - 1\n });\n this.levels = options.levels;\n } else {\n $.console.error(\"Nothing in the info.json to construct image pyramids from\");\n }\n\n if (!options.maxLevel && !this.emulateLegacyImagePyramid) {\n if (!this.scale_factors) {\n options.maxLevel = Number(Math.ceil(Math.log(Math.max(this.width, this.height), 2)));\n } else {\n options.maxLevel = Math.floor(Math.pow(Math.max.apply(null, this.scale_factors), 0.5));\n }\n }\n\n $.TileSource.apply( this, [ options ] );\n};\n\n$.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.IIIFTileSource.prototype */{\n /**\n * Determine if the data and/or url imply the image service is supported by\n * this tile source.\n * @function\n * @param {Object|Array} data\n * @param {String} optional - url\n */\n\n supports: function( data, url ) {\n // Version 2.0 and forwards\n if (data.protocol && data.protocol == 'http://iiif.io/api/image') {\n return true;\n // Version 1.1\n } else if ( data['@context'] && (\n data['@context'] == \"http://library.stanford.edu/iiif/image-api/1.1/context.json\" ||\n data['@context'] == \"http://iiif.io/api/image/1/context.json\") ) {\n // N.B. the iiif.io context is wrong, but where the representation lives so likely to be used\n return true;\n\n // Version 1.0\n } else if ( data.profile &&\n data.profile.indexOf(\"http://library.stanford.edu/iiif/image-api/compliance.html\") === 0) {\n return true;\n } else if ( data.identifier && data.width && data.height ) {\n return true;\n } else if ( data.documentElement &&\n \"info\" == data.documentElement.tagName &&\n \"http://library.stanford.edu/iiif/image-api/ns/\" ==\n data.documentElement.namespaceURI) {\n return true;\n\n // Not IIIF\n } else {\n return false;\n }\n },\n\n /**\n *\n * @function\n * @param {Object} data - the raw configuration\n * @example IIIF 1.1 Info Looks like this\n * {\n * \"@context\" : \"http://library.stanford.edu/iiif/image-api/1.1/context.json\",\n * \"@id\" : \"http://iiif.example.com/prefix/1E34750D-38DB-4825-A38A-B60A345E591C\",\n * \"width\" : 6000,\n * \"height\" : 4000,\n * \"scale_factors\" : [ 1, 2, 4 ],\n * \"tile_width\" : 1024,\n * \"tile_height\" : 1024,\n * \"formats\" : [ \"jpg\", \"png\" ],\n * \"qualities\" : [ \"native\", \"grey\" ],\n * \"profile\" : \"http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0\"\n * }\n */\n configure: function( data, url ){\n // Try to deduce our version and fake it upwards if needed\n if ( !$.isPlainObject(data) ) {\n var options = configureFromXml10( data );\n options['@context'] = \"http://iiif.io/api/image/1.0/context.json\";\n options['@id'] = url.replace('/info.xml', '');\n return options;\n } else if ( !data['@context'] ) {\n data['@context'] = 'http://iiif.io/api/image/1.0/context.json';\n data['@id'] = url.replace('/info.json', '');\n return data;\n } else {\n return data;\n }\n },\n\n /**\n * Return the tileWidth for the given level.\n * @function\n * @param {Number} level\n */\n getTileWidth: function( level ) {\n\n if(this.emulateLegacyImagePyramid) {\n return $.TileSource.prototype.getTileWidth.call(this, level);\n }\n\n var scaleFactor = Math.pow(2, this.maxLevel - level);\n\n if (this.tileSizePerScaleFactor && this.tileSizePerScaleFactor[scaleFactor]) {\n return this.tileSizePerScaleFactor[scaleFactor].width;\n }\n return this._tileWidth;\n },\n\n /**\n * Return the tileHeight for the given level.\n * @function\n * @param {Number} level\n */\n getTileHeight: function( level ) {\n\n if(this.emulateLegacyImagePyramid) {\n return $.TileSource.prototype.getTileHeight.call(this, level);\n }\n\n var scaleFactor = Math.pow(2, this.maxLevel - level);\n\n if (this.tileSizePerScaleFactor && this.tileSizePerScaleFactor[scaleFactor]) {\n return this.tileSizePerScaleFactor[scaleFactor].height;\n }\n return this._tileHeight;\n },\n\n /**\n * @function\n * @param {Number} level\n */\n getLevelScale: function ( level ) {\n\n if(this.emulateLegacyImagePyramid) {\n var levelScale = NaN;\n if (this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel) {\n levelScale =\n this.levels[level].width /\n this.levels[this.maxLevel].width;\n }\n return levelScale;\n }\n\n return $.TileSource.prototype.getLevelScale.call(this, level);\n },\n\n /**\n * @function\n * @param {Number} level\n */\n getNumTiles: function( level ) {\n\n if(this.emulateLegacyImagePyramid) {\n var scale = this.getLevelScale(level);\n if (scale) {\n return new $.Point(1, 1);\n } else {\n return new $.Point(0, 0);\n }\n }\n\n return $.TileSource.prototype.getNumTiles.call(this, level);\n },\n\n\n /**\n * @function\n * @param {Number} level\n * @param {OpenSeadragon.Point} point\n */\n getTileAtPoint: function( level, point ) {\n\n if(this.emulateLegacyImagePyramid) {\n return new $.Point(0, 0);\n }\n\n return $.TileSource.prototype.getTileAtPoint.call(this, level, point);\n },\n\n\n /**\n * Responsible for retrieving the url which will return an image for the\n * region specified by the given x, y, and level components.\n * @function\n * @param {Number} level - z index\n * @param {Number} x\n * @param {Number} y\n * @throws {Error}\n */\n getTileUrl: function( level, x, y ){\n\n if(this.emulateLegacyImagePyramid) {\n var url = null;\n if ( this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel ) {\n url = this.levels[ level ].url;\n }\n return url;\n }\n\n //# constants\n var IIIF_ROTATION = '0',\n //## get the scale (level as a decimal)\n scale = Math.pow( 0.5, this.maxLevel - level ),\n\n //# image dimensions at this level\n levelWidth = Math.ceil( this.width * scale ),\n levelHeight = Math.ceil( this.height * scale ),\n\n //## iiif region\n tileWidth,\n tileHeight,\n iiifTileSizeWidth,\n iiifTileSizeHeight,\n iiifRegion,\n iiifTileX,\n iiifTileY,\n iiifTileW,\n iiifTileH,\n iiifSize,\n iiifQuality,\n uri;\n\n tileWidth = this.getTileWidth(level);\n tileHeight = this.getTileHeight(level);\n iiifTileSizeWidth = Math.ceil( tileWidth / scale );\n iiifTileSizeHeight = Math.ceil( tileHeight / scale );\n\n if ( this['@context'].indexOf('/1.0/context.json') > -1 ||\n this['@context'].indexOf('/1.1/context.json') > -1 ||\n this['@context'].indexOf('/1/context.json') > -1 ) {\n iiifQuality = \"native.jpg\";\n } else {\n iiifQuality = \"default.jpg\";\n }\n\n if ( levelWidth < tileWidth && levelHeight < tileHeight ){\n iiifSize = levelWidth + \",\";\n iiifRegion = 'full';\n } else {\n iiifTileX = x * iiifTileSizeWidth;\n iiifTileY = y * iiifTileSizeHeight;\n iiifTileW = Math.min( iiifTileSizeWidth, this.width - iiifTileX );\n iiifTileH = Math.min( iiifTileSizeHeight, this.height - iiifTileY );\n iiifSize = Math.ceil( iiifTileW * scale ) + \",\";\n iiifRegion = [ iiifTileX, iiifTileY, iiifTileW, iiifTileH ].join( ',' );\n }\n uri = [ this['@id'], iiifRegion, iiifSize, IIIF_ROTATION, iiifQuality ].join( '/' );\n\n return uri;\n }\n\n });\n\n /**\n * Determine whether arbitrary tile requests can be made against a service with the given profile\n * @function\n * @param {object} profile - IIIF profile object\n * @throws {Error}\n */\n function canBeTiled (profile ) {\n var level0Profiles = [\n \"http://library.stanford.edu/iiif/image-api/compliance.html#level0\",\n \"http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0\",\n \"http://iiif.io/api/image/2/level0.json\"\n ];\n var isLevel0 = (level0Profiles.indexOf(profile[0]) != -1);\n return !isLevel0 || (profile.indexOf(\"sizeByW\") != -1);\n }\n\n /**\n * Build the legacy pyramid URLs (one tile per level)\n * @function\n * @param {object} options - infoJson\n * @throws {Error}\n */\n function constructLevels(options) {\n var levels = [];\n for(var i = 0; i < options.sizes.length; i++) {\n levels.push({\n url: options['@id'] + '/full/' + options.sizes[i].width + ',/0/default.jpg',\n width: options.sizes[i].width,\n height: options.sizes[i].height\n });\n }\n return levels.sort(function(a, b) {\n return a.width - b.width;\n });\n }\n\n\n function configureFromXml10(xmlDoc) {\n //parse the xml\n if ( !xmlDoc || !xmlDoc.documentElement ) {\n throw new Error( $.getString( \"Errors.Xml\" ) );\n }\n\n var root = xmlDoc.documentElement,\n rootName = root.tagName,\n configuration = null;\n\n if ( rootName == \"info\" ) {\n try {\n configuration = {};\n parseXML10( root, configuration );\n return configuration;\n\n } catch ( e ) {\n throw (e instanceof Error) ?\n e :\n new Error( $.getString(\"Errors.IIIF\") );\n }\n }\n throw new Error( $.getString( \"Errors.IIIF\" ) );\n }\n\n function parseXML10( node, configuration, property ) {\n var i,\n value;\n if ( node.nodeType == 3 && property ) {//text node\n value = node.nodeValue.trim();\n if( value.match(/^\\d*$/)){\n value = Number( value );\n }\n if( !configuration[ property ] ){\n configuration[ property ] = value;\n }else{\n if( !$.isArray( configuration[ property ] ) ){\n configuration[ property ] = [ configuration[ property ] ];\n }\n configuration[ property ].push( value );\n }\n } else if( node.nodeType == 1 ){\n for( i = 0; i < node.childNodes.length; i++ ){\n parseXML10( node.childNodes[ i ], configuration, node.nodeName );\n }\n }\n }\n\n\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - OsmTileSource\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/*\n * Derived from the OSM tile source in Rainer Simon's seajax-utils project\n * . Rainer Simon has contributed\n * the included code to the OpenSeadragon project under the New BSD license;\n * see .\n */\n\n\n(function( $ ){\n\n/**\n * @class OsmTileSource\n * @classdesc A tilesource implementation for OpenStreetMap.

      \n *\n * Note 1. Zoomlevels. Deep Zoom and OSM define zoom levels differently. In Deep\n * Zoom, level 0 equals an image of 1x1 pixels. In OSM, level 0 equals an image of\n * 256x256 levels (see http://gasi.ch/blog/inside-deep-zoom-2). I.e. there is a\n * difference of log2(256)=8 levels.

      \n *\n * Note 2. Image dimension. According to the OSM Wiki\n * (http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Zoom_levels)\n * the highest Mapnik zoom level has 256.144x256.144 tiles, with a 256x256\n * pixel size. I.e. the Deep Zoom image dimension is 65.572.864x65.572.864\n * pixels.\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.TileSource\n * @param {Number|Object} width - the pixel width of the image or the idiomatic\n * options object which is used instead of positional arguments.\n * @param {Number} height\n * @param {Number} tileSize\n * @param {Number} tileOverlap\n * @param {String} tilesUrl\n */\n$.OsmTileSource = function( width, height, tileSize, tileOverlap, tilesUrl ) {\n var options;\n\n if( $.isPlainObject( width ) ){\n options = width;\n }else{\n options = {\n width: arguments[0],\n height: arguments[1],\n tileSize: arguments[2],\n tileOverlap: arguments[3],\n tilesUrl: arguments[4]\n };\n }\n //apply default setting for standard public OpenStreatMaps service\n //but allow them to be specified so fliks can host there own instance\n //or apply against other services supportting the same standard\n if( !options.width || !options.height ){\n options.width = 65572864;\n options.height = 65572864;\n }\n if( !options.tileSize ){\n options.tileSize = 256;\n options.tileOverlap = 0;\n }\n if( !options.tilesUrl ){\n options.tilesUrl = \"http://tile.openstreetmap.org/\";\n }\n options.minLevel = 8;\n\n $.TileSource.apply( this, [ options ] );\n\n};\n\n$.extend( $.OsmTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.OsmTileSource.prototype */{\n\n\n /**\n * Determine if the data and/or url imply the image service is supported by\n * this tile source.\n * @function\n * @param {Object|Array} data\n * @param {String} optional - url\n */\n supports: function( data, url ){\n return (\n data.type &&\n \"openstreetmaps\" == data.type\n );\n },\n\n /**\n *\n * @function\n * @param {Object} data - the raw configuration\n * @param {String} url - the url the data was retreived from if any.\n * @return {Object} options - A dictionary of keyword arguments sufficient\n * to configure this tile sources constructor.\n */\n configure: function( data, url ){\n return data;\n },\n\n\n /**\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n */\n getTileUrl: function( level, x, y ) {\n return this.tilesUrl + (level - 8) + \"/\" + x + \"/\" + y + \".png\";\n }\n});\n\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - TmsTileSource\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/*\n * Derived from the TMS tile source in Rainer Simon's seajax-utils project\n * . Rainer Simon has contributed\n * the included code to the OpenSeadragon project under the New BSD license;\n * see .\n */\n\n\n(function( $ ){\n\n/**\n * @class TmsTileSource\n * @classdesc A tilesource implementation for Tiled Map Services (TMS).\n * TMS tile scheme ( [ as supported by OpenLayers ] is described here\n * ( http://openlayers.org/dev/examples/tms.html ).\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.TileSource\n * @param {Number|Object} width - the pixel width of the image or the idiomatic\n * options object which is used instead of positional arguments.\n * @param {Number} height\n * @param {Number} tileSize\n * @param {Number} tileOverlap\n * @param {String} tilesUrl\n */\n$.TmsTileSource = function( width, height, tileSize, tileOverlap, tilesUrl ) {\n var options;\n\n if( $.isPlainObject( width ) ){\n options = width;\n }else{\n options = {\n width: arguments[0],\n height: arguments[1],\n tileSize: arguments[2],\n tileOverlap: arguments[3],\n tilesUrl: arguments[4]\n };\n }\n // TMS has integer multiples of 256 for width/height and adds buffer\n // if necessary -> account for this!\n var bufferedWidth = Math.ceil(options.width / 256) * 256,\n bufferedHeight = Math.ceil(options.height / 256) * 256,\n max;\n\n // Compute number of zoomlevels in this tileset\n if (bufferedWidth > bufferedHeight) {\n max = bufferedWidth / 256;\n } else {\n max = bufferedHeight / 256;\n }\n options.maxLevel = Math.ceil(Math.log(max) / Math.log(2)) - 1;\n options.tileSize = 256;\n options.width = bufferedWidth;\n options.height = bufferedHeight;\n\n $.TileSource.apply( this, [ options ] );\n\n};\n\n$.extend( $.TmsTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.TmsTileSource.prototype */{\n\n\n /**\n * Determine if the data and/or url imply the image service is supported by\n * this tile source.\n * @function\n * @param {Object|Array} data\n * @param {String} optional - url\n */\n supports: function( data, url ){\n return ( data.type && \"tiledmapservice\" == data.type );\n },\n\n /**\n *\n * @function\n * @param {Object} data - the raw configuration\n * @param {String} url - the url the data was retreived from if any.\n * @return {Object} options - A dictionary of keyword arguments sufficient\n * to configure this tile sources constructor.\n */\n configure: function( data, url ){\n return data;\n },\n\n\n /**\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n */\n getTileUrl: function( level, x, y ) {\n // Convert from Deep Zoom definition to TMS zoom definition\n var yTiles = this.getNumTiles( level ).y - 1;\n\n return this.tilesUrl + level + \"/\" + x + \"/\" + (yTiles - y) + \".png\";\n }\n});\n\n\n}( OpenSeadragon ));\n","(function($) {\n\n /**\n * @class ZoomifyTileSource\n * @classdesc A tilesource implementation for the zoomify format.\n *\n * A description of the format can be found here:\n * https://ecommons.cornell.edu/bitstream/handle/1813/5410/Introducing_Zoomify_Image.pdf\n *\n * There are two ways of creating a zoomify tilesource for openseadragon\n *\n * 1) Supplying all necessary information in the tilesource object. A minimal example object for this method looks like this:\n *\n * {\n * type: \"zoomifytileservice\",\n * width: 1000,\n * height: 1000,\n * tilesUrl: \"/test/data/zoomify/\"\n * }\n *\n * The tileSize is currently hardcoded to 256 (the usual Zoomify default). The tileUrl must the path to the image _directory_.\n *\n * 2) Loading image metadata from xml file: (CURRENTLY NOT SUPPORTED)\n *\n * When creating zoomify formatted images one \"xml\" like file with name ImageProperties.xml\n * will be created as well. Here is an example of such a file:\n *\n * \n *\n * To use this xml file as metadata source you must supply the path to the ImageProperties.xml file and leave out all other parameters:\n * As stated above, this method of loading a zoomify tilesource is currently not supported\n *\n * {\n * type: \"zoomifytileservice\",\n * tilesUrl: \"/test/data/zoomify/ImageProperties.xml\"\n * }\n\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.TileSource\n * @param {Number} width - the pixel width of the image.\n * @param {Number} height\n * @param {Number} tileSize\n * @param {String} tilesUrl\n */\n $.ZoomifyTileSource = function(options) {\n options.tileSize = 256;\n\n var currentImageSize = {\n x: options.width,\n y: options.height\n };\n options.imageSizes = [{\n x: options.width,\n y: options.height\n }];\n options.gridSize = [this._getGridSize(options.width, options.height, options.tileSize)];\n\n while (parseInt(currentImageSize.x, 10) > options.tileSize || parseInt(currentImageSize.y, 10) > options.tileSize) {\n currentImageSize.x = Math.floor(currentImageSize.x / 2);\n currentImageSize.y = Math.floor(currentImageSize.y / 2);\n options.imageSizes.push({\n x: currentImageSize.x,\n y: currentImageSize.y\n });\n options.gridSize.push(this._getGridSize(currentImageSize.x, currentImageSize.y, options.tileSize));\n }\n options.imageSizes.reverse();\n options.gridSize.reverse();\n options.minLevel = 0;\n options.maxLevel = options.gridSize.length - 1;\n\n OpenSeadragon.TileSource.apply(this, [options]);\n };\n\n $.extend($.ZoomifyTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.ZoomifyTileSource.prototype */ {\n\n //private\n _getGridSize: function(width, height, tileSize) {\n return {\n x: Math.ceil(width / tileSize),\n y: Math.ceil(height / tileSize)\n };\n },\n\n //private\n _calculateAbsoluteTileNumber: function(level, x, y) {\n var num = 0;\n var size = {};\n\n //Sum up all tiles below the level we want the number of tiles\n for (var z = 0; z < level; z++) {\n size = this.gridSize[z];\n num += size.x * size.y;\n }\n //Add the tiles of the level\n size = this.gridSize[level];\n num += size.x * y + x;\n return num;\n },\n\n /**\n * Determine if the data and/or url imply the image service is supported by\n * this tile source.\n * @function\n * @param {Object|Array} data\n * @param {String} optional - url\n */\n supports: function(data, url) {\n return (data.type && \"zoomifytileservice\" == data.type);\n },\n\n /**\n *\n * @function\n * @param {Object} data - the raw configuration\n * @param {String} url - the url the data was retreived from if any.\n * @return {Object} options - A dictionary of keyword arguments sufficient\n * to configure this tile sources constructor.\n */\n configure: function(data, url) {\n return data;\n },\n\n /**\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n */\n getTileUrl: function(level, x, y) {\n //console.log(level);\n var result = 0;\n var num = this._calculateAbsoluteTileNumber(level, x, y);\n result = Math.floor(num / 256);\n return this.tilesUrl + 'TileGroup' + result + '/' + level + '-' + x + '-' + y + '.jpg';\n\n }\n });\n\n}(OpenSeadragon));\n\n","/*\n * OpenSeadragon - LegacyTileSource\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class LegacyTileSource\n * @classdesc The LegacyTileSource allows simple, traditional image pyramids to be loaded\n * into an OpenSeadragon Viewer. Basically, this translates to the historically\n * common practice of starting with a 'master' image, maybe a tiff for example,\n * and generating a set of 'service' images like one or more thumbnails, a medium\n * resolution image and a high resolution image in standard web formats like\n * png or jpg.\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.TileSource\n * @param {Array} levels An array of file descriptions, each is an object with\n * a 'url', a 'width', and a 'height'. Overriding classes can expect more\n * properties but these properties are sufficient for this implementation.\n * Additionally, the levels are required to be listed in order from\n * smallest to largest.\n * @property {Number} aspectRatio\n * @property {Number} dimensions\n * @property {Number} tileSize\n * @property {Number} tileOverlap\n * @property {Number} minLevel\n * @property {Number} maxLevel\n * @property {Array} levels\n */\n$.LegacyTileSource = function( levels ) {\n\n var options,\n width,\n height;\n\n if( $.isArray( levels ) ){\n options = {\n type: 'legacy-image-pyramid',\n levels: levels\n };\n }\n\n //clean up the levels to make sure we support all formats\n options.levels = filterFiles( options.levels );\n\n if ( options.levels.length > 0 ) {\n width = options.levels[ options.levels.length - 1 ].width;\n height = options.levels[ options.levels.length - 1 ].height;\n }\n else {\n width = 0;\n height = 0;\n $.console.error( \"No supported image formats found\" );\n }\n\n $.extend( true, options, {\n width: width,\n height: height,\n tileSize: Math.max( height, width ),\n tileOverlap: 0,\n minLevel: 0,\n maxLevel: options.levels.length > 0 ? options.levels.length - 1 : 0\n } );\n\n $.TileSource.apply( this, [ options ] );\n\n this.levels = options.levels;\n};\n\n$.extend( $.LegacyTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.LegacyTileSource.prototype */{\n /**\n * Determine if the data and/or url imply the image service is supported by\n * this tile source.\n * @function\n * @param {Object|Array} data\n * @param {String} optional - url\n */\n supports: function( data, url ){\n return (\n data.type &&\n \"legacy-image-pyramid\" == data.type\n ) || (\n data.documentElement &&\n \"legacy-image-pyramid\" == data.documentElement.getAttribute('type')\n );\n },\n\n\n /**\n *\n * @function\n * @param {Object|XMLDocument} configuration - the raw configuration\n * @param {String} dataUrl - the url the data was retreived from if any.\n * @return {Object} options - A dictionary of keyword arguments sufficient\n * to configure this tile sources constructor.\n */\n configure: function( configuration, dataUrl ){\n\n var options;\n\n if( !$.isPlainObject(configuration) ){\n\n options = configureFromXML( this, configuration );\n\n }else{\n\n options = configureFromObject( this, configuration );\n }\n\n return options;\n\n },\n\n /**\n * @function\n * @param {Number} level\n */\n getLevelScale: function ( level ) {\n var levelScale = NaN;\n if ( this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel ) {\n levelScale =\n this.levels[ level ].width /\n this.levels[ this.maxLevel ].width;\n }\n return levelScale;\n },\n\n /**\n * @function\n * @param {Number} level\n */\n getNumTiles: function( level ) {\n var scale = this.getLevelScale( level );\n if ( scale ){\n return new $.Point( 1, 1 );\n } else {\n return new $.Point( 0, 0 );\n }\n },\n\n /**\n * This method is not implemented by this class other than to throw an Error\n * announcing you have to implement it. Because of the variety of tile\n * server technologies, and various specifications for building image\n * pyramids, this method is here to allow easy integration.\n * @function\n * @param {Number} level\n * @param {Number} x\n * @param {Number} y\n * @throws {Error}\n */\n getTileUrl: function ( level, x, y ) {\n var url = null;\n if ( this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel ) {\n url = this.levels[ level ].url;\n }\n return url;\n }\n} );\n\n/**\n * This method removes any files from the Array which dont conform to our\n * basic requirements for a 'level' in the LegacyTileSource.\n * @private\n * @inner\n * @function\n */\nfunction filterFiles( files ){\n var filtered = [],\n file,\n i;\n for( i = 0; i < files.length; i++ ){\n file = files[ i ];\n if( file.height &&\n file.width &&\n file.url ){\n //This is sufficient to serve as a level\n filtered.push({\n url: file.url,\n width: Number( file.width ),\n height: Number( file.height )\n });\n }\n else {\n $.console.error( 'Unsupported image format: %s', file.url ? file.url : '' );\n }\n }\n\n return filtered.sort(function(a, b) {\n return a.height - b.height;\n });\n\n}\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction configureFromXML( tileSource, xmlDoc ){\n\n if ( !xmlDoc || !xmlDoc.documentElement ) {\n throw new Error( $.getString( \"Errors.Xml\" ) );\n }\n\n var root = xmlDoc.documentElement,\n rootName = root.tagName,\n conf = null,\n levels = [],\n level,\n i;\n\n if ( rootName == \"image\" ) {\n\n try {\n conf = {\n type: root.getAttribute( \"type\" ),\n levels: []\n };\n\n levels = root.getElementsByTagName( \"level\" );\n for ( i = 0; i < levels.length; i++ ) {\n level = levels[ i ];\n\n conf.levels.push({\n url: level.getAttribute( \"url\" ),\n width: parseInt( level.getAttribute( \"width\" ), 10 ),\n height: parseInt( level.getAttribute( \"height\" ), 10 )\n });\n }\n\n return configureFromObject( tileSource, conf );\n\n } catch ( e ) {\n throw (e instanceof Error) ?\n e :\n new Error( 'Unknown error parsing Legacy Image Pyramid XML.' );\n }\n } else if ( rootName == \"collection\" ) {\n throw new Error( 'Legacy Image Pyramid Collections not yet supported.' );\n } else if ( rootName == \"error\" ) {\n throw new Error( 'Error: ' + xmlDoc );\n }\n\n throw new Error( 'Unknown element ' + rootName );\n}\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction configureFromObject( tileSource, configuration ){\n\n return configuration.levels;\n\n}\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - ImageTileSource\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function ($) {\n\n /**\n * @class ImageTileSource\n * @classdesc The ImageTileSource allows a simple image to be loaded\n * into an OpenSeadragon Viewer.\n * There are 2 ways to open an ImageTileSource:\n * 1. viewer.open({type: 'image', url: fooUrl});\n * 2. viewer.open(new OpenSeadragon.ImageTileSource({url: fooUrl}));\n *\n * With the first syntax, the crossOriginPolicy, ajaxWithCredentials and\n * useCanvas options are inherited from the viewer if they are not\n * specified directly in the options object.\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.TileSource\n * @param {Object} options Options object.\n * @param {String} options.url URL of the image\n * @param {Boolean} [options.buildPyramid=true] If set to true (default), a\n * pyramid will be built internally to provide a better downsampling.\n * @param {String|Boolean} [options.crossOriginPolicy=false] Valid values are\n * 'Anonymous', 'use-credentials', and false. If false, image requests will\n * not use CORS preventing internal pyramid building for images from other\n * domains.\n * @param {String|Boolean} [options.ajaxWithCredentials=false] Whether to set\n * the withCredentials XHR flag for AJAX requests (when loading tile sources).\n * @param {Boolean} [options.useCanvas=true] Set to false to prevent any use\n * of the canvas API.\n */\n $.ImageTileSource = function (options) {\n\n options = $.extend({\n buildPyramid: true,\n crossOriginPolicy: false,\n ajaxWithCredentials: false,\n useCanvas: true\n }, options);\n $.TileSource.apply(this, [options]);\n\n };\n\n $.extend($.ImageTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.ImageTileSource.prototype */{\n /**\n * Determine if the data and/or url imply the image service is supported by\n * this tile source.\n * @function\n * @param {Object|Array} data\n * @param {String} optional - url\n */\n supports: function (data, url) {\n return data.type && data.type === \"image\";\n },\n /**\n *\n * @function\n * @param {Object} options - the options\n * @param {String} dataUrl - the url the image was retreived from, if any.\n * @return {Object} options - A dictionary of keyword arguments sufficient\n * to configure this tile sources constructor.\n */\n configure: function (options, dataUrl) {\n return options;\n },\n /**\n * Responsible for retrieving, and caching the\n * image metadata pertinent to this TileSources implementation.\n * @function\n * @param {String} url\n * @throws {Error}\n */\n getImageInfo: function (url) {\n var image = this._image = new Image();\n var _this = this;\n\n if (this.crossOriginPolicy) {\n image.crossOrigin = this.crossOriginPolicy;\n }\n if (this.ajaxWithCredentials) {\n image.useCredentials = this.ajaxWithCredentials;\n }\n\n $.addEvent(image, 'load', function () {\n /* IE8 fix since it has no naturalWidth and naturalHeight */\n _this.width = Object.prototype.hasOwnProperty.call(image, 'naturalWidth') ? image.naturalWidth : image.width;\n _this.height = Object.prototype.hasOwnProperty.call(image, 'naturalHeight') ? image.naturalHeight : image.height;\n _this.aspectRatio = _this.width / _this.height;\n _this.dimensions = new $.Point(_this.width, _this.height);\n _this._tileWidth = _this.width;\n _this._tileHeight = _this.height;\n _this.tileOverlap = 0;\n _this.minLevel = 0;\n _this.levels = _this._buildLevels();\n _this.maxLevel = _this.levels.length - 1;\n\n _this.ready = true;\n\n // Note: this event is documented elsewhere, in TileSource\n _this.raiseEvent('ready', {tileSource: _this});\n });\n\n $.addEvent(image, 'error', function () {\n // Note: this event is documented elsewhere, in TileSource\n _this.raiseEvent('open-failed', {\n message: \"Error loading image at \" + url,\n source: url\n });\n });\n\n image.src = url;\n },\n /**\n * @function\n * @param {Number} level\n */\n getLevelScale: function (level) {\n var levelScale = NaN;\n if (level >= this.minLevel && level <= this.maxLevel) {\n levelScale =\n this.levels[level].width /\n this.levels[this.maxLevel].width;\n }\n return levelScale;\n },\n /**\n * @function\n * @param {Number} level\n */\n getNumTiles: function (level) {\n var scale = this.getLevelScale(level);\n if (scale) {\n return new $.Point(1, 1);\n } else {\n return new $.Point(0, 0);\n }\n },\n /**\n * Retrieves a tile url\n * @function\n * @param {Number} level Level of the tile\n * @param {Number} x x coordinate of the tile\n * @param {Number} y y coordinate of the tile\n */\n getTileUrl: function (level, x, y) {\n var url = null;\n if (level >= this.minLevel && level <= this.maxLevel) {\n url = this.levels[level].url;\n }\n return url;\n },\n /**\n * Retrieves a tile context 2D\n * @function\n * @param {Number} level Level of the tile\n * @param {Number} x x coordinate of the tile\n * @param {Number} y y coordinate of the tile\n */\n getContext2D: function (level, x, y) {\n var context = null;\n if (level >= this.minLevel && level <= this.maxLevel) {\n context = this.levels[level].context2D;\n }\n return context;\n },\n\n // private\n //\n // Builds the differents levels of the pyramid if possible\n // (i.e. if canvas API enabled and no canvas tainting issue).\n _buildLevels: function () {\n var levels = [{\n url: this._image.src,\n /* IE8 fix since it has no naturalWidth and naturalHeight */\n width: Object.prototype.hasOwnProperty.call(this._image, 'naturalWidth') ? this._image.naturalWidth : this._image.width,\n height: Object.prototype.hasOwnProperty.call(this._image, 'naturalHeight') ? this._image.naturalHeight : this._image.height\n }];\n\n if (!this.buildPyramid || !$.supportsCanvas || !this.useCanvas) {\n // We don't need the image anymore. Allows it to be GC.\n delete this._image;\n return levels;\n }\n\n /* IE8 fix since it has no naturalWidth and naturalHeight */\n var currentWidth = Object.prototype.hasOwnProperty.call(this._image, 'naturalWidth') ? this._image.naturalWidth : this._image.width;\n var currentHeight = Object.prototype.hasOwnProperty.call(this._image, 'naturalHeight') ? this._image.naturalHeight : this._image.height;\n\n\n var bigCanvas = document.createElement(\"canvas\");\n var bigContext = bigCanvas.getContext(\"2d\");\n\n bigCanvas.width = currentWidth;\n bigCanvas.height = currentHeight;\n bigContext.drawImage(this._image, 0, 0, currentWidth, currentHeight);\n // We cache the context of the highest level because the browser\n // is a lot faster at downsampling something it already has\n // downsampled before.\n levels[0].context2D = bigContext;\n // We don't need the image anymore. Allows it to be GC.\n delete this._image;\n\n if ($.isCanvasTainted(bigCanvas)) {\n // If the canvas is tainted, we can't compute the pyramid.\n return levels;\n }\n\n // We build smaller levels until either width or height becomes\n // 1 pixel wide.\n while (currentWidth >= 2 && currentHeight >= 2) {\n currentWidth = Math.floor(currentWidth / 2);\n currentHeight = Math.floor(currentHeight / 2);\n var smallCanvas = document.createElement(\"canvas\");\n var smallContext = smallCanvas.getContext(\"2d\");\n smallCanvas.width = currentWidth;\n smallCanvas.height = currentHeight;\n smallContext.drawImage(bigCanvas, 0, 0, currentWidth, currentHeight);\n\n levels.splice(0, 0, {\n context2D: smallContext,\n width: currentWidth,\n height: currentHeight\n });\n\n bigCanvas = smallCanvas;\n bigContext = smallContext;\n }\n return levels;\n }\n });\n\n}(OpenSeadragon));\n","/*\n * OpenSeadragon - TileSourceCollection\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function($) {\n\n// deprecated\n$.TileSourceCollection = function(tileSize, tileSources, rows, layout) {\n $.console.error('TileSourceCollection is deprecated; use World instead');\n};\n\n}(OpenSeadragon));\n","/*\n * OpenSeadragon - Button\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * An enumeration of button states\n * @member ButtonState\n * @memberof OpenSeadragon\n * @static\n * @type {Object}\n * @property {Number} REST\n * @property {Number} GROUP\n * @property {Number} HOVER\n * @property {Number} DOWN\n */\n$.ButtonState = {\n REST: 0,\n GROUP: 1,\n HOVER: 2,\n DOWN: 3\n};\n\n/**\n * @class Button\n * @classdesc Manages events, hover states for individual buttons, tool-tips, as well\n * as fading the buttons out when the user has not interacted with them\n * for a specified period.\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.EventSource\n * @param {Object} options\n * @param {Element} [options.element=null] Element to use as the button. If not specified, an HTML <div> element is created.\n * @param {String} [options.tooltip=null] Provides context help for the button when the\n * user hovers over it.\n * @param {String} [options.srcRest=null] URL of image to use in 'rest' state.\n * @param {String} [options.srcGroup=null] URL of image to use in 'up' state.\n * @param {String} [options.srcHover=null] URL of image to use in 'hover' state.\n * @param {String} [options.srcDown=null] URL of image to use in 'down' state.\n * @param {Number} [options.fadeDelay=0] How long to wait before fading.\n * @param {Number} [options.fadeLength=2000] How long should it take to fade the button.\n * @param {OpenSeadragon.EventHandler} [options.onPress=null] Event handler callback for {@link OpenSeadragon.Button.event:press}.\n * @param {OpenSeadragon.EventHandler} [options.onRelease=null] Event handler callback for {@link OpenSeadragon.Button.event:release}.\n * @param {OpenSeadragon.EventHandler} [options.onClick=null] Event handler callback for {@link OpenSeadragon.Button.event:click}.\n * @param {OpenSeadragon.EventHandler} [options.onEnter=null] Event handler callback for {@link OpenSeadragon.Button.event:enter}.\n * @param {OpenSeadragon.EventHandler} [options.onExit=null] Event handler callback for {@link OpenSeadragon.Button.event:exit}.\n * @param {OpenSeadragon.EventHandler} [options.onFocus=null] Event handler callback for {@link OpenSeadragon.Button.event:focus}.\n * @param {OpenSeadragon.EventHandler} [options.onBlur=null] Event handler callback for {@link OpenSeadragon.Button.event:blur}.\n */\n$.Button = function( options ) {\n\n var _this = this;\n\n $.EventSource.call( this );\n\n $.extend( true, this, {\n\n tooltip: null,\n srcRest: null,\n srcGroup: null,\n srcHover: null,\n srcDown: null,\n clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold,\n clickDistThreshold: $.DEFAULT_SETTINGS.clickDistThreshold,\n /**\n * How long to wait before fading.\n * @member {Number} fadeDelay\n * @memberof OpenSeadragon.Button#\n */\n fadeDelay: 0,\n /**\n * How long should it take to fade the button.\n * @member {Number} fadeLength\n * @memberof OpenSeadragon.Button#\n */\n fadeLength: 2000,\n onPress: null,\n onRelease: null,\n onClick: null,\n onEnter: null,\n onExit: null,\n onFocus: null,\n onBlur: null\n\n }, options );\n\n /**\n * The button element.\n * @member {Element} element\n * @memberof OpenSeadragon.Button#\n */\n this.element = options.element || $.makeNeutralElement(\"div\");\n\n //if the user has specified the element to bind the control to explicitly\n //then do not add the default control images\n if ( !options.element ) {\n this.imgRest = $.makeTransparentImage( this.srcRest );\n this.imgGroup = $.makeTransparentImage( this.srcGroup );\n this.imgHover = $.makeTransparentImage( this.srcHover );\n this.imgDown = $.makeTransparentImage( this.srcDown );\n\n this.imgRest.alt =\n this.imgGroup.alt =\n this.imgHover.alt =\n this.imgDown.alt =\n this.tooltip;\n\n this.element.style.position = \"relative\";\n $.setElementTouchActionNone( this.element );\n\n this.imgGroup.style.position =\n this.imgHover.style.position =\n this.imgDown.style.position =\n \"absolute\";\n\n this.imgGroup.style.top =\n this.imgHover.style.top =\n this.imgDown.style.top =\n \"0px\";\n\n this.imgGroup.style.left =\n this.imgHover.style.left =\n this.imgDown.style.left =\n \"0px\";\n\n this.imgHover.style.visibility =\n this.imgDown.style.visibility =\n \"hidden\";\n\n if ($.Browser.vendor == $.BROWSERS.FIREFOX && $.Browser.version < 3) {\n this.imgGroup.style.top =\n this.imgHover.style.top =\n this.imgDown.style.top =\n \"\";\n }\n\n this.element.appendChild( this.imgRest );\n this.element.appendChild( this.imgGroup );\n this.element.appendChild( this.imgHover );\n this.element.appendChild( this.imgDown );\n }\n\n\n this.addHandler(\"press\", this.onPress);\n this.addHandler(\"release\", this.onRelease);\n this.addHandler(\"click\", this.onClick);\n this.addHandler(\"enter\", this.onEnter);\n this.addHandler(\"exit\", this.onExit);\n this.addHandler(\"focus\", this.onFocus);\n this.addHandler(\"blur\", this.onBlur);\n\n /**\n * The button's current state.\n * @member {OpenSeadragon.ButtonState} currentState\n * @memberof OpenSeadragon.Button#\n */\n this.currentState = $.ButtonState.GROUP;\n\n // When the button last began to fade.\n this.fadeBeginTime = null;\n // Whether this button should fade after user stops interacting with the viewport.\n this.shouldFade = false;\n\n this.element.style.display = \"inline-block\";\n this.element.style.position = \"relative\";\n this.element.title = this.tooltip;\n\n /**\n * Tracks mouse/touch/key events on the button.\n * @member {OpenSeadragon.MouseTracker} tracker\n * @memberof OpenSeadragon.Button#\n */\n this.tracker = new $.MouseTracker({\n\n element: this.element,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n\n enterHandler: function( event ) {\n if ( event.insideElementPressed ) {\n inTo( _this, $.ButtonState.DOWN );\n /**\n * Raised when the cursor enters the Button element.\n *\n * @event enter\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( \"enter\", { originalEvent: event.originalEvent } );\n } else if ( !event.buttonDownAny ) {\n inTo( _this, $.ButtonState.HOVER );\n }\n },\n\n focusHandler: function ( event ) {\n this.enterHandler( event );\n /**\n * Raised when the Button element receives focus.\n *\n * @event focus\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( \"focus\", { originalEvent: event.originalEvent } );\n },\n\n exitHandler: function( event ) {\n outTo( _this, $.ButtonState.GROUP );\n if ( event.insideElementPressed ) {\n /**\n * Raised when the cursor leaves the Button element.\n *\n * @event exit\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( \"exit\", { originalEvent: event.originalEvent } );\n }\n },\n\n blurHandler: function ( event ) {\n this.exitHandler( event );\n /**\n * Raised when the Button element loses focus.\n *\n * @event blur\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( \"blur\", { originalEvent: event.originalEvent } );\n },\n\n pressHandler: function ( event ) {\n inTo( _this, $.ButtonState.DOWN );\n /**\n * Raised when a mouse button is pressed or touch occurs in the Button element.\n *\n * @event press\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( \"press\", { originalEvent: event.originalEvent } );\n },\n\n releaseHandler: function( event ) {\n if ( event.insideElementPressed && event.insideElementReleased ) {\n outTo( _this, $.ButtonState.HOVER );\n /**\n * Raised when the mouse button is released or touch ends in the Button element.\n *\n * @event release\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( \"release\", { originalEvent: event.originalEvent } );\n } else if ( event.insideElementPressed ) {\n outTo( _this, $.ButtonState.GROUP );\n } else {\n inTo( _this, $.ButtonState.HOVER );\n }\n },\n\n clickHandler: function( event ) {\n if ( event.quick ) {\n /**\n * Raised when a mouse button is pressed and released or touch is initiated and ended in the Button element within the time and distance threshold.\n *\n * @event click\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent(\"click\", { originalEvent: event.originalEvent });\n }\n },\n\n keyHandler: function( event ){\n //console.log( \"%s : handling key %s!\", _this.tooltip, event.keyCode);\n if( 13 === event.keyCode ){\n /***\n * Raised when a mouse button is pressed and released or touch is initiated and ended in the Button element within the time and distance threshold.\n *\n * @event click\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( \"click\", { originalEvent: event.originalEvent } );\n /***\n * Raised when the mouse button is released or touch ends in the Button element.\n *\n * @event release\n * @memberof OpenSeadragon.Button\n * @type {object}\n * @property {OpenSeadragon.Button} eventSource - A reference to the Button which raised the event.\n * @property {Object} originalEvent - The original DOM event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.raiseEvent( \"release\", { originalEvent: event.originalEvent } );\n return false;\n }\n return true;\n }\n\n });\n\n outTo( this, $.ButtonState.REST );\n};\n\n$.extend( $.Button.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.Button.prototype */{\n\n /**\n * TODO: Determine what this function is intended to do and if it's actually\n * useful as an API point.\n * @function\n */\n notifyGroupEnter: function() {\n inTo( this, $.ButtonState.GROUP );\n },\n\n /**\n * TODO: Determine what this function is intended to do and if it's actually\n * useful as an API point.\n * @function\n */\n notifyGroupExit: function() {\n outTo( this, $.ButtonState.REST );\n },\n\n /**\n * @function\n */\n disable: function(){\n this.notifyGroupExit();\n this.element.disabled = true;\n $.setElementOpacity( this.element, 0.2, true );\n },\n\n /**\n * @function\n */\n enable: function(){\n this.element.disabled = false;\n $.setElementOpacity( this.element, 1.0, true );\n this.notifyGroupEnter();\n }\n\n});\n\n\nfunction scheduleFade( button ) {\n $.requestAnimationFrame(function(){\n updateFade( button );\n });\n}\n\nfunction updateFade( button ) {\n var currentTime,\n deltaTime,\n opacity;\n\n if ( button.shouldFade ) {\n currentTime = $.now();\n deltaTime = currentTime - button.fadeBeginTime;\n opacity = 1.0 - deltaTime / button.fadeLength;\n opacity = Math.min( 1.0, opacity );\n opacity = Math.max( 0.0, opacity );\n\n if( button.imgGroup ){\n $.setElementOpacity( button.imgGroup, opacity, true );\n }\n if ( opacity > 0 ) {\n // fade again\n scheduleFade( button );\n }\n }\n}\n\nfunction beginFading( button ) {\n button.shouldFade = true;\n button.fadeBeginTime = $.now() + button.fadeDelay;\n window.setTimeout( function(){\n scheduleFade( button );\n }, button.fadeDelay );\n}\n\nfunction stopFading( button ) {\n button.shouldFade = false;\n if( button.imgGroup ){\n $.setElementOpacity( button.imgGroup, 1.0, true );\n }\n}\n\nfunction inTo( button, newState ) {\n\n if( button.element.disabled ){\n return;\n }\n\n if ( newState >= $.ButtonState.GROUP &&\n button.currentState == $.ButtonState.REST ) {\n stopFading( button );\n button.currentState = $.ButtonState.GROUP;\n }\n\n if ( newState >= $.ButtonState.HOVER &&\n button.currentState == $.ButtonState.GROUP ) {\n if( button.imgHover ){\n button.imgHover.style.visibility = \"\";\n }\n button.currentState = $.ButtonState.HOVER;\n }\n\n if ( newState >= $.ButtonState.DOWN &&\n button.currentState == $.ButtonState.HOVER ) {\n if( button.imgDown ){\n button.imgDown.style.visibility = \"\";\n }\n button.currentState = $.ButtonState.DOWN;\n }\n}\n\n\nfunction outTo( button, newState ) {\n\n if( button.element.disabled ){\n return;\n }\n\n if ( newState <= $.ButtonState.HOVER &&\n button.currentState == $.ButtonState.DOWN ) {\n if( button.imgDown ){\n button.imgDown.style.visibility = \"hidden\";\n }\n button.currentState = $.ButtonState.HOVER;\n }\n\n if ( newState <= $.ButtonState.GROUP &&\n button.currentState == $.ButtonState.HOVER ) {\n if( button.imgHover ){\n button.imgHover.style.visibility = \"hidden\";\n }\n button.currentState = $.ButtonState.GROUP;\n }\n\n if ( newState <= $.ButtonState.REST &&\n button.currentState == $.ButtonState.GROUP ) {\n beginFading( button );\n button.currentState = $.ButtonState.REST;\n }\n}\n\n\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - ButtonGroup\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n/**\n * @class ButtonGroup\n * @classdesc Manages events on groups of buttons.\n *\n * @memberof OpenSeadragon\n * @param {Object} options - A dictionary of settings applied against the entire group of buttons.\n * @param {Array} options.buttons Array of buttons\n * @param {Element} [options.element] Element to use as the container\n **/\n$.ButtonGroup = function( options ) {\n\n $.extend( true, this, {\n /**\n * An array containing the buttons themselves.\n * @member {Array} buttons\n * @memberof OpenSeadragon.ButtonGroup#\n */\n buttons: [],\n clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold,\n clickDistThreshold: $.DEFAULT_SETTINGS.clickDistThreshold,\n labelText: \"\"\n }, options );\n\n // copy the button elements TODO: Why?\n var buttons = this.buttons.concat([]),\n _this = this,\n i;\n\n /**\n * The shared container for the buttons.\n * @member {Element} element\n * @memberof OpenSeadragon.ButtonGroup#\n */\n this.element = options.element || $.makeNeutralElement( \"div\" );\n\n // TODO What if there IS an options.group specified?\n if( !options.group ){\n this.label = $.makeNeutralElement( \"label\" );\n //TODO: support labels for ButtonGroups\n //this.label.innerHTML = this.labelText;\n this.element.style.display = \"inline-block\";\n this.element.appendChild( this.label );\n for ( i = 0; i < buttons.length; i++ ) {\n this.element.appendChild( buttons[ i ].element );\n }\n }\n\n $.setElementTouchActionNone( this.element );\n\n /**\n * Tracks mouse/touch/key events accross the group of buttons.\n * @member {OpenSeadragon.MouseTracker} tracker\n * @memberof OpenSeadragon.ButtonGroup#\n */\n this.tracker = new $.MouseTracker({\n element: this.element,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n enterHandler: function ( event ) {\n var i;\n for ( i = 0; i < _this.buttons.length; i++ ) {\n _this.buttons[ i ].notifyGroupEnter();\n }\n },\n exitHandler: function ( event ) {\n var i;\n if ( !event.insideElementPressed ) {\n for ( i = 0; i < _this.buttons.length; i++ ) {\n _this.buttons[ i ].notifyGroupExit();\n }\n }\n },\n });\n};\n\n/** @lends OpenSeadragon.ButtonGroup.prototype */\n$.ButtonGroup.prototype = {\n\n /**\n * TODO: Figure out why this is used on the public API and if a more useful\n * api can be created.\n * @function\n * @private\n */\n emulateEnter: function() {\n this.tracker.enterHandler( { eventSource: this.tracker } );\n },\n\n /**\n * TODO: Figure out why this is used on the public API and if a more useful\n * api can be created.\n * @function\n * @private\n */\n emulateExit: function() {\n this.tracker.exitHandler( { eventSource: this.tracker } );\n }\n};\n\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - Rect\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function($) {\n\n/**\n * @class Rect\n * @classdesc A Rectangle is described by it top left coordinates (x, y), width,\n * height and degrees of rotation around (x, y).\n * Note that the coordinate system used is the one commonly used with images:\n * x increases when going to the right\n * y increases when going to the bottom\n * degrees increases clockwise with 0 being the horizontal\n *\n * The constructor normalizes the rectangle to always have 0 <= degrees < 90\n *\n * @memberof OpenSeadragon\n * @param {Number} [x=0] The vector component 'x'.\n * @param {Number} [y=0] The vector component 'y'.\n * @param {Number} [width=0] The vector component 'width'.\n * @param {Number} [height=0] The vector component 'height'.\n * @param {Number} [degrees=0] Rotation of the rectangle around (x,y) in degrees.\n */\n$.Rect = function(x, y, width, height, degrees) {\n /**\n * The vector component 'x'.\n * @member {Number} x\n * @memberof OpenSeadragon.Rect#\n */\n this.x = typeof(x) === \"number\" ? x : 0;\n /**\n * The vector component 'y'.\n * @member {Number} y\n * @memberof OpenSeadragon.Rect#\n */\n this.y = typeof(y) === \"number\" ? y : 0;\n /**\n * The vector component 'width'.\n * @member {Number} width\n * @memberof OpenSeadragon.Rect#\n */\n this.width = typeof(width) === \"number\" ? width : 0;\n /**\n * The vector component 'height'.\n * @member {Number} height\n * @memberof OpenSeadragon.Rect#\n */\n this.height = typeof(height) === \"number\" ? height : 0;\n\n this.degrees = typeof(degrees) === \"number\" ? degrees : 0;\n\n // Normalizes the rectangle.\n this.degrees = $.positiveModulo(this.degrees, 360);\n var newTopLeft, newWidth;\n if (this.degrees >= 270) {\n newTopLeft = this.getTopRight();\n this.x = newTopLeft.x;\n this.y = newTopLeft.y;\n newWidth = this.height;\n this.height = this.width;\n this.width = newWidth;\n this.degrees -= 270;\n } else if (this.degrees >= 180) {\n newTopLeft = this.getBottomRight();\n this.x = newTopLeft.x;\n this.y = newTopLeft.y;\n this.degrees -= 180;\n } else if (this.degrees >= 90) {\n newTopLeft = this.getBottomLeft();\n this.x = newTopLeft.x;\n this.y = newTopLeft.y;\n newWidth = this.height;\n this.height = this.width;\n this.width = newWidth;\n this.degrees -= 90;\n }\n};\n\n/**\n * Builds a rectangle having the 3 specified points as summits.\n * @static\n * @memberof OpenSeadragon.Rect\n * @param {OpenSeadragon.Point} topLeft\n * @param {OpenSeadragon.Point} topRight\n * @param {OpenSeadragon.Point} bottomLeft\n * @returns {OpenSeadragon.Rect}\n */\n$.Rect.fromSummits = function(topLeft, topRight, bottomLeft) {\n var width = topLeft.distanceTo(topRight);\n var height = topLeft.distanceTo(bottomLeft);\n var diff = topRight.minus(topLeft);\n var radians = Math.atan(diff.y / diff.x);\n if (diff.x < 0) {\n radians += Math.PI;\n } else if (diff.y < 0) {\n radians += 2 * Math.PI;\n }\n return new $.Rect(\n topLeft.x,\n topLeft.y,\n width,\n height,\n radians / Math.PI * 180);\n};\n\n/** @lends OpenSeadragon.Rect.prototype */\n$.Rect.prototype = {\n /**\n * @function\n * @returns {OpenSeadragon.Rect} a duplicate of this Rect\n */\n clone: function() {\n return new $.Rect(\n this.x,\n this.y,\n this.width,\n this.height,\n this.degrees);\n },\n\n /**\n * The aspect ratio is simply the ratio of width to height.\n * @function\n * @returns {Number} The ratio of width to height.\n */\n getAspectRatio: function() {\n return this.width / this.height;\n },\n\n /**\n * Provides the coordinates of the upper-left corner of the rectangle as a\n * point.\n * @function\n * @returns {OpenSeadragon.Point} The coordinate of the upper-left corner of\n * the rectangle.\n */\n getTopLeft: function() {\n return new $.Point(\n this.x,\n this.y\n );\n },\n\n /**\n * Provides the coordinates of the bottom-right corner of the rectangle as a\n * point.\n * @function\n * @returns {OpenSeadragon.Point} The coordinate of the bottom-right corner of\n * the rectangle.\n */\n getBottomRight: function() {\n return new $.Point(this.x + this.width, this.y + this.height)\n .rotate(this.degrees, this.getTopLeft());\n },\n\n /**\n * Provides the coordinates of the top-right corner of the rectangle as a\n * point.\n * @function\n * @returns {OpenSeadragon.Point} The coordinate of the top-right corner of\n * the rectangle.\n */\n getTopRight: function() {\n return new $.Point(this.x + this.width, this.y)\n .rotate(this.degrees, this.getTopLeft());\n },\n\n /**\n * Provides the coordinates of the bottom-left corner of the rectangle as a\n * point.\n * @function\n * @returns {OpenSeadragon.Point} The coordinate of the bottom-left corner of\n * the rectangle.\n */\n getBottomLeft: function() {\n return new $.Point(this.x, this.y + this.height)\n .rotate(this.degrees, this.getTopLeft());\n },\n\n /**\n * Computes the center of the rectangle.\n * @function\n * @returns {OpenSeadragon.Point} The center of the rectangle as represented\n * as represented by a 2-dimensional vector (x,y)\n */\n getCenter: function() {\n return new $.Point(\n this.x + this.width / 2.0,\n this.y + this.height / 2.0\n ).rotate(this.degrees, this.getTopLeft());\n },\n\n /**\n * Returns the width and height component as a vector OpenSeadragon.Point\n * @function\n * @returns {OpenSeadragon.Point} The 2 dimensional vector representing the\n * the width and height of the rectangle.\n */\n getSize: function() {\n return new $.Point(this.width, this.height);\n },\n\n /**\n * Determines if two Rectangles have equivalent components.\n * @function\n * @param {OpenSeadragon.Rect} rectangle The Rectangle to compare to.\n * @return {Boolean} 'true' if all components are equal, otherwise 'false'.\n */\n equals: function(other) {\n return (other instanceof $.Rect) &&\n this.x === other.x &&\n this.y === other.y &&\n this.width === other.width &&\n this.height === other.height &&\n this.degrees === other.degrees;\n },\n\n /**\n * Multiply all dimensions (except degrees) in this Rect by a factor and\n * return a new Rect.\n * @function\n * @param {Number} factor The factor to multiply vector components.\n * @returns {OpenSeadragon.Rect} A new rect representing the multiplication\n * of the vector components by the factor\n */\n times: function(factor) {\n return new $.Rect(\n this.x * factor,\n this.y * factor,\n this.width * factor,\n this.height * factor,\n this.degrees);\n },\n\n /**\n * Translate/move this Rect by a vector and return new Rect.\n * @function\n * @param {OpenSeadragon.Point} delta The translation vector.\n * @returns {OpenSeadragon.Rect} A new rect with altered position\n */\n translate: function(delta) {\n return new $.Rect(\n this.x + delta.x,\n this.y + delta.y,\n this.width,\n this.height,\n this.degrees);\n },\n\n /**\n * Returns the smallest rectangle that will contain this and the given\n * rectangle bounding boxes.\n * @param {OpenSeadragon.Rect} rect\n * @return {OpenSeadragon.Rect} The new rectangle.\n */\n union: function(rect) {\n var thisBoundingBox = this.getBoundingBox();\n var otherBoundingBox = rect.getBoundingBox();\n\n var left = Math.min(thisBoundingBox.x, otherBoundingBox.x);\n var top = Math.min(thisBoundingBox.y, otherBoundingBox.y);\n var right = Math.max(\n thisBoundingBox.x + thisBoundingBox.width,\n otherBoundingBox.x + otherBoundingBox.width);\n var bottom = Math.max(\n thisBoundingBox.y + thisBoundingBox.height,\n otherBoundingBox.y + otherBoundingBox.height);\n\n return new $.Rect(\n left,\n top,\n right - left,\n bottom - top);\n },\n\n /**\n * Returns the bounding box of the intersection of this rectangle with the\n * given rectangle.\n * @param {OpenSeadragon.Rect} rect\n * @return {OpenSeadragon.Rect} the bounding box of the intersection\n * or null if the rectangles don't intersect.\n */\n intersection: function(rect) {\n // Simplified version of Weiler Atherton clipping algorithm\n // https://en.wikipedia.org/wiki/Weiler%E2%80%93Atherton_clipping_algorithm\n // Because we just want the bounding box of the intersection,\n // we can just compute the bounding box of:\n // 1. all the summits of this which are inside rect\n // 2. all the summits of rect which are inside this\n // 3. all the intersections of rect and this\n var EPSILON = 0.0000000001;\n\n var intersectionPoints = [];\n\n var thisTopLeft = this.getTopLeft();\n if (rect.containsPoint(thisTopLeft, EPSILON)) {\n intersectionPoints.push(thisTopLeft);\n }\n var thisTopRight = this.getTopRight();\n if (rect.containsPoint(thisTopRight, EPSILON)) {\n intersectionPoints.push(thisTopRight);\n }\n var thisBottomLeft = this.getBottomLeft();\n if (rect.containsPoint(thisBottomLeft, EPSILON)) {\n intersectionPoints.push(thisBottomLeft);\n }\n var thisBottomRight = this.getBottomRight();\n if (rect.containsPoint(thisBottomRight, EPSILON)) {\n intersectionPoints.push(thisBottomRight);\n }\n\n var rectTopLeft = rect.getTopLeft();\n if (this.containsPoint(rectTopLeft, EPSILON)) {\n intersectionPoints.push(rectTopLeft);\n }\n var rectTopRight = rect.getTopRight();\n if (this.containsPoint(rectTopRight, EPSILON)) {\n intersectionPoints.push(rectTopRight);\n }\n var rectBottomLeft = rect.getBottomLeft();\n if (this.containsPoint(rectBottomLeft, EPSILON)) {\n intersectionPoints.push(rectBottomLeft);\n }\n var rectBottomRight = rect.getBottomRight();\n if (this.containsPoint(rectBottomRight, EPSILON)) {\n intersectionPoints.push(rectBottomRight);\n }\n\n var thisSegments = this._getSegments();\n var rectSegments = rect._getSegments();\n for (var i = 0; i < thisSegments.length; i++) {\n var thisSegment = thisSegments[i];\n for (var j = 0; j < rectSegments.length; j++) {\n var rectSegment = rectSegments[j];\n var intersect = getIntersection(thisSegment[0], thisSegment[1],\n rectSegment[0], rectSegment[1]);\n if (intersect) {\n intersectionPoints.push(intersect);\n }\n }\n }\n\n // Get intersection point of segments [a,b] and [c,d]\n function getIntersection(a, b, c, d) {\n // http://stackoverflow.com/a/1968345/1440403\n var abVector = b.minus(a);\n var cdVector = d.minus(c);\n\n var denom = -cdVector.x * abVector.y + abVector.x * cdVector.y;\n if (denom === 0) {\n return null;\n }\n\n var s = (abVector.x * (a.y - c.y) - abVector.y * (a.x - c.x)) / denom;\n var t = (cdVector.x * (a.y - c.y) - cdVector.y * (a.x - c.x)) / denom;\n\n if (-EPSILON <= s && s <= 1 - EPSILON &&\n -EPSILON <= t && t <= 1 - EPSILON) {\n return new $.Point(a.x + t * abVector.x, a.y + t * abVector.y);\n }\n return null;\n }\n\n if (intersectionPoints.length === 0) {\n return null;\n }\n\n var minX = intersectionPoints[0].x;\n var maxX = intersectionPoints[0].x;\n var minY = intersectionPoints[0].y;\n var maxY = intersectionPoints[0].y;\n for (var k = 1; k < intersectionPoints.length; k++) {\n var point = intersectionPoints[k];\n if (point.x < minX) {\n minX = point.x;\n }\n if (point.x > maxX) {\n maxX = point.x;\n }\n if (point.y < minY) {\n minY = point.y;\n }\n if (point.y > maxY) {\n maxY = point.y;\n }\n }\n return new $.Rect(minX, minY, maxX - minX, maxY - minY);\n },\n\n // private\n _getSegments: function() {\n var topLeft = this.getTopLeft();\n var topRight = this.getTopRight();\n var bottomLeft = this.getBottomLeft();\n var bottomRight = this.getBottomRight();\n return [[topLeft, topRight],\n [topRight, bottomRight],\n [bottomRight, bottomLeft],\n [bottomLeft, topLeft]];\n },\n\n /**\n * Rotates a rectangle around a point.\n * @function\n * @param {Number} degrees The angle in degrees to rotate.\n * @param {OpenSeadragon.Point} [pivot] The point about which to rotate.\n * Defaults to the center of the rectangle.\n * @return {OpenSeadragon.Rect}\n */\n rotate: function(degrees, pivot) {\n degrees = $.positiveModulo(degrees, 360);\n if (degrees === 0) {\n return this.clone();\n }\n\n pivot = pivot || this.getCenter();\n var newTopLeft = this.getTopLeft().rotate(degrees, pivot);\n var newTopRight = this.getTopRight().rotate(degrees, pivot);\n\n var diff = newTopRight.minus(newTopLeft);\n // Handle floating point error\n diff = diff.apply(function(x) {\n var EPSILON = 1e-15;\n return Math.abs(x) < EPSILON ? 0 : x;\n });\n var radians = Math.atan(diff.y / diff.x);\n if (diff.x < 0) {\n radians += Math.PI;\n } else if (diff.y < 0) {\n radians += 2 * Math.PI;\n }\n return new $.Rect(\n newTopLeft.x,\n newTopLeft.y,\n this.width,\n this.height,\n radians / Math.PI * 180);\n },\n\n /**\n * Retrieves the smallest horizontal (degrees=0) rectangle which contains\n * this rectangle.\n * @returns {OpenSeadragon.Rect}\n */\n getBoundingBox: function() {\n if (this.degrees === 0) {\n return this.clone();\n }\n var topLeft = this.getTopLeft();\n var topRight = this.getTopRight();\n var bottomLeft = this.getBottomLeft();\n var bottomRight = this.getBottomRight();\n var minX = Math.min(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x);\n var maxX = Math.max(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x);\n var minY = Math.min(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y);\n var maxY = Math.max(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y);\n return new $.Rect(\n minX,\n minY,\n maxX - minX,\n maxY - minY);\n },\n\n /**\n * Retrieves the smallest horizontal (degrees=0) rectangle which contains\n * this rectangle and has integers x, y, width and height\n * @returns {OpenSeadragon.Rect}\n */\n getIntegerBoundingBox: function() {\n var boundingBox = this.getBoundingBox();\n var x = Math.floor(boundingBox.x);\n var y = Math.floor(boundingBox.y);\n var width = Math.ceil(boundingBox.width + boundingBox.x - x);\n var height = Math.ceil(boundingBox.height + boundingBox.y - y);\n return new $.Rect(x, y, width, height);\n },\n\n /**\n * Determines whether a point is inside this rectangle (edge included).\n * @function\n * @param {OpenSeadragon.Point} point\n * @param {Number} [epsilon=0] the margin of error allowed\n * @returns {Boolean} true if the point is inside this rectangle, false\n * otherwise.\n */\n containsPoint: function(point, epsilon) {\n epsilon = epsilon || 0;\n\n // See http://stackoverflow.com/a/2752754/1440403 for explanation\n var topLeft = this.getTopLeft();\n var topRight = this.getTopRight();\n var bottomLeft = this.getBottomLeft();\n var topDiff = topRight.minus(topLeft);\n var leftDiff = bottomLeft.minus(topLeft);\n\n return ((point.x - topLeft.x) * topDiff.x +\n (point.y - topLeft.y) * topDiff.y >= -epsilon) &&\n\n ((point.x - topRight.x) * topDiff.x +\n (point.y - topRight.y) * topDiff.y <= epsilon) &&\n\n ((point.x - topLeft.x) * leftDiff.x +\n (point.y - topLeft.y) * leftDiff.y >= -epsilon) &&\n\n ((point.x - bottomLeft.x) * leftDiff.x +\n (point.y - bottomLeft.y) * leftDiff.y <= epsilon);\n },\n\n /**\n * Provides a string representation of the rectangle which is useful for\n * debugging.\n * @function\n * @returns {String} A string representation of the rectangle.\n */\n toString: function() {\n return \"[\" +\n (Math.round(this.x * 100) / 100) + \", \" +\n (Math.round(this.y * 100) / 100) + \", \" +\n (Math.round(this.width * 100) / 100) + \"x\" +\n (Math.round(this.height * 100) / 100) + \", \" +\n (Math.round(this.degrees * 100) / 100) + \"deg\" +\n \"]\";\n }\n};\n\n\n}(OpenSeadragon));\n","/*\n * OpenSeadragon - ReferenceStrip\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function ( $ ) {\n\n// dictionary from id to private properties\nvar THIS = {};\n\n/**\n * The CollectionDrawer is a reimplementation if the Drawer API that\n * focuses on allowing a viewport to be redefined as a collection\n * of smaller viewports, defined by a clear number of rows and / or\n * columns of which each item in the matrix of viewports has its own\n * source.\n *\n * This idea is a reexpression of the idea of dzi collections\n * which allows a clearer algorithm to reuse the tile sources already\n * supported by OpenSeadragon, in heterogenious or homogenious\n * sequences just like mixed groups already supported by the viewer\n * for the purpose of image sequnces.\n *\n * TODO: The difficult part of this feature is figuring out how to express\n * this functionality as a combination of the functionality already\n * provided by Drawer, Viewport, TileSource, and Navigator. It may\n * require better abstraction at those points in order to effeciently\n * reuse those paradigms.\n */\n/**\n * @class ReferenceStrip\n * @memberof OpenSeadragon\n * @param {Object} options\n */\n$.ReferenceStrip = function ( options ) {\n\n var _this = this,\n viewer = options.viewer,\n viewerSize = $.getElementSize( viewer.element ),\n element,\n style,\n i;\n\n //We may need to create a new element and id if they did not\n //provide the id for the existing element\n if ( !options.id ) {\n options.id = 'referencestrip-' + $.now();\n this.element = $.makeNeutralElement( \"div\" );\n this.element.id = options.id;\n this.element.className = 'referencestrip';\n }\n\n options = $.extend( true, {\n sizeRatio: $.DEFAULT_SETTINGS.referenceStripSizeRatio,\n position: $.DEFAULT_SETTINGS.referenceStripPosition,\n scroll: $.DEFAULT_SETTINGS.referenceStripScroll,\n clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold\n }, options, {\n //required overrides\n element: this.element,\n //These need to be overridden to prevent recursion since\n //the navigator is a viewer and a viewer has a navigator\n showNavigator: false,\n mouseNavEnabled: false,\n showNavigationControl: false,\n showSequenceControl: false\n } );\n\n $.extend( this, options );\n //Private state properties\n THIS[this.id] = {\n \"animating\": false\n };\n\n this.minPixelRatio = this.viewer.minPixelRatio;\n\n style = this.element.style;\n style.marginTop = '0px';\n style.marginRight = '0px';\n style.marginBottom = '0px';\n style.marginLeft = '0px';\n style.left = '0px';\n style.bottom = '0px';\n style.border = '0px';\n style.background = '#000';\n style.position = 'relative';\n\n $.setElementTouchActionNone( this.element );\n\n $.setElementOpacity( this.element, 0.8 );\n\n this.viewer = viewer;\n this.innerTracker = new $.MouseTracker( {\n element: this.element,\n dragHandler: $.delegate( this, onStripDrag ),\n scrollHandler: $.delegate( this, onStripScroll ),\n enterHandler: $.delegate( this, onStripEnter ),\n exitHandler: $.delegate( this, onStripExit ),\n keyDownHandler: $.delegate( this, onKeyDown ),\n keyHandler: $.delegate( this, onKeyPress )\n } );\n\n //Controls the position and orientation of the reference strip and sets the\n //appropriate width and height\n if ( options.width && options.height ) {\n this.element.style.width = options.width + 'px';\n this.element.style.height = options.height + 'px';\n viewer.addControl(\n this.element,\n { anchor: $.ControlAnchor.BOTTOM_LEFT }\n );\n } else {\n if ( \"horizontal\" == options.scroll ) {\n this.element.style.width = (\n viewerSize.x *\n options.sizeRatio *\n viewer.tileSources.length\n ) + ( 12 * viewer.tileSources.length ) + 'px';\n\n this.element.style.height = (\n viewerSize.y *\n options.sizeRatio\n ) + 'px';\n\n viewer.addControl(\n this.element,\n { anchor: $.ControlAnchor.BOTTOM_LEFT }\n );\n } else {\n this.element.style.height = (\n viewerSize.y *\n options.sizeRatio *\n viewer.tileSources.length\n ) + ( 12 * viewer.tileSources.length ) + 'px';\n\n this.element.style.width = (\n viewerSize.x *\n options.sizeRatio\n ) + 'px';\n\n viewer.addControl(\n this.element,\n { anchor: $.ControlAnchor.TOP_LEFT }\n );\n\n }\n }\n\n this.panelWidth = ( viewerSize.x * this.sizeRatio ) + 8;\n this.panelHeight = ( viewerSize.y * this.sizeRatio ) + 8;\n this.panels = [];\n this.miniViewers = {};\n\n /*jshint loopfunc:true*/\n for ( i = 0; i < viewer.tileSources.length; i++ ) {\n\n element = $.makeNeutralElement( 'div' );\n element.id = this.element.id + \"-\" + i;\n\n element.style.width = _this.panelWidth + 'px';\n element.style.height = _this.panelHeight + 'px';\n element.style.display = 'inline';\n element.style.float = 'left'; //Webkit\n element.style.cssFloat = 'left'; //Firefox\n element.style.styleFloat = 'left'; //IE\n element.style.padding = '2px';\n $.setElementTouchActionNone( element );\n\n element.innerTracker = new $.MouseTracker( {\n element: element,\n clickTimeThreshold: this.clickTimeThreshold,\n clickDistThreshold: this.clickDistThreshold,\n pressHandler: function ( event ) {\n event.eventSource.dragging = $.now();\n },\n releaseHandler: function ( event ) {\n var tracker = event.eventSource,\n id = tracker.element.id,\n page = Number( id.split( '-' )[2] ),\n now = $.now();\n\n if ( event.insideElementPressed &&\n event.insideElementReleased &&\n tracker.dragging &&\n ( now - tracker.dragging ) < tracker.clickTimeThreshold ) {\n tracker.dragging = null;\n viewer.goToPage( page );\n }\n }\n } );\n\n this.element.appendChild( element );\n\n element.activePanel = false;\n\n this.panels.push( element );\n\n }\n loadPanels( this, this.scroll == 'vertical' ? viewerSize.y : viewerSize.x, 0 );\n this.setFocus( 0 );\n\n};\n\n$.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.ReferenceStrip.prototype */{\n\n /**\n * @function\n */\n setFocus: function ( page ) {\n var element = $.getElement( this.element.id + '-' + page ),\n viewerSize = $.getElementSize( this.viewer.canvas ),\n scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ),\n scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ),\n offsetLeft = -Number( this.element.style.marginLeft.replace( 'px', '' ) ),\n offsetTop = -Number( this.element.style.marginTop.replace( 'px', '' ) ),\n offset;\n\n if ( this.currentSelected !== element ) {\n if ( this.currentSelected ) {\n this.currentSelected.style.background = '#000';\n }\n this.currentSelected = element;\n this.currentSelected.style.background = '#999';\n\n if ( 'horizontal' == this.scroll ) {\n //right left\n offset = ( Number( page ) ) * ( this.panelWidth + 3 );\n if ( offset > offsetLeft + viewerSize.x - this.panelWidth ) {\n offset = Math.min( offset, ( scrollWidth - viewerSize.x ) );\n this.element.style.marginLeft = -offset + 'px';\n loadPanels( this, viewerSize.x, -offset );\n } else if ( offset < offsetLeft ) {\n offset = Math.max( 0, offset - viewerSize.x / 2 );\n this.element.style.marginLeft = -offset + 'px';\n loadPanels( this, viewerSize.x, -offset );\n }\n } else {\n offset = ( Number( page ) ) * ( this.panelHeight + 3 );\n if ( offset > offsetTop + viewerSize.y - this.panelHeight ) {\n offset = Math.min( offset, ( scrollHeight - viewerSize.y ) );\n this.element.style.marginTop = -offset + 'px';\n loadPanels( this, viewerSize.y, -offset );\n } else if ( offset < offsetTop ) {\n offset = Math.max( 0, offset - viewerSize.y / 2 );\n this.element.style.marginTop = -offset + 'px';\n loadPanels( this, viewerSize.y, -offset );\n }\n }\n\n this.currentPage = page;\n onStripEnter.call( this, { eventSource: this.innerTracker } );\n }\n },\n\n /**\n * @function\n */\n update: function () {\n if ( THIS[this.id].animating ) {\n $.console.log( 'image reference strip update' );\n return true;\n }\n return false;\n },\n\n // Overrides Viewer.destroy\n destroy: function() {\n if (this.miniViewers) {\n for (var key in this.miniViewers) {\n this.miniViewers[key].destroy();\n }\n }\n\n if (this.element) {\n this.element.parentNode.removeChild(this.element);\n }\n }\n\n} );\n\n\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onStripDrag( event ) {\n\n var offsetLeft = Number( this.element.style.marginLeft.replace( 'px', '' ) ),\n offsetTop = Number( this.element.style.marginTop.replace( 'px', '' ) ),\n scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ),\n scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ),\n viewerSize = $.getElementSize( this.viewer.canvas );\n this.dragging = true;\n if ( this.element ) {\n if ( 'horizontal' == this.scroll ) {\n if ( -event.delta.x > 0 ) {\n //forward\n if ( offsetLeft > -( scrollWidth - viewerSize.x ) ) {\n this.element.style.marginLeft = ( offsetLeft + ( event.delta.x * 2 ) ) + 'px';\n loadPanels( this, viewerSize.x, offsetLeft + ( event.delta.x * 2 ) );\n }\n } else if ( -event.delta.x < 0 ) {\n //reverse\n if ( offsetLeft < 0 ) {\n this.element.style.marginLeft = ( offsetLeft + ( event.delta.x * 2 ) ) + 'px';\n loadPanels( this, viewerSize.x, offsetLeft + ( event.delta.x * 2 ) );\n }\n }\n } else {\n if ( -event.delta.y > 0 ) {\n //forward\n if ( offsetTop > -( scrollHeight - viewerSize.y ) ) {\n this.element.style.marginTop = ( offsetTop + ( event.delta.y * 2 ) ) + 'px';\n loadPanels( this, viewerSize.y, offsetTop + ( event.delta.y * 2 ) );\n }\n } else if ( -event.delta.y < 0 ) {\n //reverse\n if ( offsetTop < 0 ) {\n this.element.style.marginTop = ( offsetTop + ( event.delta.y * 2 ) ) + 'px';\n loadPanels( this, viewerSize.y, offsetTop + ( event.delta.y * 2 ) );\n }\n }\n }\n }\n return false;\n\n}\n\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onStripScroll( event ) {\n var offsetLeft = Number( this.element.style.marginLeft.replace( 'px', '' ) ),\n offsetTop = Number( this.element.style.marginTop.replace( 'px', '' ) ),\n scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ),\n scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ),\n viewerSize = $.getElementSize( this.viewer.canvas );\n if ( this.element ) {\n if ( 'horizontal' == this.scroll ) {\n if ( event.scroll > 0 ) {\n //forward\n if ( offsetLeft > -( scrollWidth - viewerSize.x ) ) {\n this.element.style.marginLeft = ( offsetLeft - ( event.scroll * 60 ) ) + 'px';\n loadPanels( this, viewerSize.x, offsetLeft - ( event.scroll * 60 ) );\n }\n } else if ( event.scroll < 0 ) {\n //reverse\n if ( offsetLeft < 0 ) {\n this.element.style.marginLeft = ( offsetLeft - ( event.scroll * 60 ) ) + 'px';\n loadPanels( this, viewerSize.x, offsetLeft - ( event.scroll * 60 ) );\n }\n }\n } else {\n if ( event.scroll < 0 ) {\n //scroll up\n if ( offsetTop > viewerSize.y - scrollHeight ) {\n this.element.style.marginTop = ( offsetTop + ( event.scroll * 60 ) ) + 'px';\n loadPanels( this, viewerSize.y, offsetTop + ( event.scroll * 60 ) );\n }\n } else if ( event.scroll > 0 ) {\n //scroll dowm\n if ( offsetTop < 0 ) {\n this.element.style.marginTop = ( offsetTop + ( event.scroll * 60 ) ) + 'px';\n loadPanels( this, viewerSize.y, offsetTop + ( event.scroll * 60 ) );\n }\n }\n }\n }\n //cancels event\n return false;\n}\n\n\nfunction loadPanels( strip, viewerSize, scroll ) {\n var panelSize,\n activePanelsStart,\n activePanelsEnd,\n miniViewer,\n style,\n i,\n element;\n if ( 'horizontal' == strip.scroll ) {\n panelSize = strip.panelWidth;\n } else {\n panelSize = strip.panelHeight;\n }\n activePanelsStart = Math.ceil( viewerSize / panelSize ) + 5;\n activePanelsEnd = Math.ceil( ( Math.abs( scroll ) + viewerSize ) / panelSize ) + 1;\n activePanelsStart = activePanelsEnd - activePanelsStart;\n activePanelsStart = activePanelsStart < 0 ? 0 : activePanelsStart;\n\n for ( i = activePanelsStart; i < activePanelsEnd && i < strip.panels.length; i++ ) {\n element = strip.panels[i];\n if ( !element.activePanel ) {\n var miniTileSource;\n var originalTileSource = strip.viewer.tileSources[i];\n if (originalTileSource.referenceStripThumbnailUrl) {\n miniTileSource = {\n type: 'image',\n url: originalTileSource.referenceStripThumbnailUrl\n };\n } else {\n miniTileSource = originalTileSource;\n }\n miniViewer = new $.Viewer( {\n id: element.id,\n tileSources: [miniTileSource],\n element: element,\n navigatorSizeRatio: strip.sizeRatio,\n showNavigator: false,\n mouseNavEnabled: false,\n showNavigationControl: false,\n showSequenceControl: false,\n immediateRender: true,\n blendTime: 0,\n animationTime: 0\n } );\n\n miniViewer.displayRegion = $.makeNeutralElement( \"div\" );\n miniViewer.displayRegion.id = element.id + '-displayregion';\n miniViewer.displayRegion.className = 'displayregion';\n\n style = miniViewer.displayRegion.style;\n style.position = 'relative';\n style.top = '0px';\n style.left = '0px';\n style.fontSize = '0px';\n style.overflow = 'hidden';\n style.float = 'left'; //Webkit\n style.cssFloat = 'left'; //Firefox\n style.styleFloat = 'left'; //IE\n style.zIndex = 999999999;\n style.cursor = 'default';\n style.width = ( strip.panelWidth - 4 ) + 'px';\n style.height = ( strip.panelHeight - 4 ) + 'px';\n\n // TODO: What is this for? Future keyboard navigation support?\n miniViewer.displayRegion.innerTracker = new $.MouseTracker( {\n element: miniViewer.displayRegion,\n startDisabled: true\n } );\n\n element.getElementsByTagName( 'div' )[0].appendChild(\n miniViewer.displayRegion\n );\n\n strip.miniViewers[element.id] = miniViewer;\n\n element.activePanel = true;\n }\n }\n}\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onStripEnter( event ) {\n var element = event.eventSource.element;\n\n //$.setElementOpacity(element, 0.8);\n\n //element.style.border = '1px solid #555';\n //element.style.background = '#000';\n\n if ( 'horizontal' == this.scroll ) {\n\n //element.style.paddingTop = \"0px\";\n element.style.marginBottom = \"0px\";\n\n } else {\n\n //element.style.paddingRight = \"0px\";\n element.style.marginLeft = \"0px\";\n\n }\n return false;\n}\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onStripExit( event ) {\n var element = event.eventSource.element;\n\n if ( 'horizontal' == this.scroll ) {\n\n //element.style.paddingTop = \"10px\";\n element.style.marginBottom = \"-\" + ( $.getElementSize( element ).y / 2 ) + \"px\";\n\n } else {\n\n //element.style.paddingRight = \"10px\";\n element.style.marginLeft = \"-\" + ( $.getElementSize( element ).x / 2 ) + \"px\";\n\n }\n return false;\n}\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onKeyDown( event ) {\n //console.log( event.keyCode );\n\n if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) {\n switch ( event.keyCode ) {\n case 38: //up arrow\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );\n return false;\n case 40: //down arrow\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );\n return false;\n case 37: //left arrow\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );\n return false;\n case 39: //right arrow\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );\n return false;\n default:\n //console.log( 'navigator keycode %s', event.keyCode );\n return true;\n }\n } else {\n return true;\n }\n}\n\n\n/**\n * @private\n * @inner\n * @function\n */\nfunction onKeyPress( event ) {\n //console.log( event.keyCode );\n\n if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) {\n switch ( event.keyCode ) {\n case 61: //=|+\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );\n return false;\n case 45: //-|_\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );\n return false;\n case 48: //0|)\n case 119: //w\n case 87: //W\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );\n return false;\n case 115: //s\n case 83: //S\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );\n return false;\n case 97: //a\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } );\n return false;\n case 100: //d\n onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } );\n return false;\n default:\n //console.log( 'navigator keycode %s', event.keyCode );\n return true;\n }\n } else {\n return true;\n }\n}\n\n}(OpenSeadragon));\n","/*\n * OpenSeadragon - DisplayRect\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class DisplayRect\n * @classdesc A display rectangle is very similar to {@link OpenSeadragon.Rect} but adds two\n * fields, 'minLevel' and 'maxLevel' which denote the supported zoom levels\n * for this rectangle.\n *\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.Rect\n * @param {Number} x The vector component 'x'.\n * @param {Number} y The vector component 'y'.\n * @param {Number} width The vector component 'height'.\n * @param {Number} height The vector component 'width'.\n * @param {Number} minLevel The lowest zoom level supported.\n * @param {Number} maxLevel The highest zoom level supported.\n */\n$.DisplayRect = function( x, y, width, height, minLevel, maxLevel ) {\n $.Rect.apply( this, [ x, y, width, height ] );\n\n /**\n * The lowest zoom level supported.\n * @member {Number} minLevel\n * @memberof OpenSeadragon.DisplayRect#\n */\n this.minLevel = minLevel;\n /**\n * The highest zoom level supported.\n * @member {Number} maxLevel\n * @memberof OpenSeadragon.DisplayRect#\n */\n this.maxLevel = maxLevel;\n};\n\n$.extend( $.DisplayRect.prototype, $.Rect.prototype );\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - Spring\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class Spring\n * @memberof OpenSeadragon\n * @param {Object} options - Spring configuration settings.\n * @param {Number} options.springStiffness - Spring stiffness. Must be greater than zero.\n * The closer to zero, the closer to linear animation.\n * @param {Number} options.animationTime - Animation duration per spring, in seconds.\n * Must be zero or greater.\n * @param {Number} [options.initial=0] - Initial value of spring.\n * @param {Boolean} [options.exponential=false] - Whether this spring represents\n * an exponential scale (such as zoom) and should be animated accordingly. Note that\n * exponential springs must have non-zero values.\n */\n$.Spring = function( options ) {\n var args = arguments;\n\n if( typeof( options ) != 'object' ){\n //allows backward compatible use of ( initialValue, config ) as\n //constructor parameters\n options = {\n initial: args.length && typeof ( args[ 0 ] ) == \"number\" ?\n args[ 0 ] :\n undefined,\n /**\n * Spring stiffness.\n * @member {Number} springStiffness\n * @memberof OpenSeadragon.Spring#\n */\n springStiffness: args.length > 1 ?\n args[ 1 ].springStiffness :\n 5.0,\n /**\n * Animation duration per spring.\n * @member {Number} animationTime\n * @memberof OpenSeadragon.Spring#\n */\n animationTime: args.length > 1 ?\n args[ 1 ].animationTime :\n 1.5\n };\n }\n\n $.console.assert(typeof options.springStiffness === \"number\" && options.springStiffness !== 0,\n \"[OpenSeadragon.Spring] options.springStiffness must be a non-zero number\");\n\n $.console.assert(typeof options.animationTime === \"number\" && options.animationTime >= 0,\n \"[OpenSeadragon.Spring] options.animationTime must be a number greater than or equal to 0\");\n\n if (options.exponential) {\n this._exponential = true;\n delete options.exponential;\n }\n\n $.extend( true, this, options);\n\n /**\n * @member {Object} current\n * @memberof OpenSeadragon.Spring#\n * @property {Number} value\n * @property {Number} time\n */\n this.current = {\n value: typeof ( this.initial ) == \"number\" ?\n this.initial :\n (this._exponential ? 0 : 1),\n time: $.now() // always work in milliseconds\n };\n\n $.console.assert(!this._exponential || this.current.value !== 0,\n \"[OpenSeadragon.Spring] value must be non-zero for exponential springs\");\n\n /**\n * @member {Object} start\n * @memberof OpenSeadragon.Spring#\n * @property {Number} value\n * @property {Number} time\n */\n this.start = {\n value: this.current.value,\n time: this.current.time\n };\n\n /**\n * @member {Object} target\n * @memberof OpenSeadragon.Spring#\n * @property {Number} value\n * @property {Number} time\n */\n this.target = {\n value: this.current.value,\n time: this.current.time\n };\n\n if (this._exponential) {\n this.start._logValue = Math.log(this.start.value);\n this.target._logValue = Math.log(this.target.value);\n this.current._logValue = Math.log(this.current.value);\n }\n};\n\n/** @lends OpenSeadragon.Spring.prototype */\n$.Spring.prototype = {\n\n /**\n * @function\n * @param {Number} target\n */\n resetTo: function( target ) {\n $.console.assert(!this._exponential || target !== 0,\n \"[OpenSeadragon.Spring.resetTo] target must be non-zero for exponential springs\");\n\n this.start.value = this.target.value = this.current.value = target;\n this.start.time = this.target.time = this.current.time = $.now();\n\n if (this._exponential) {\n this.start._logValue = Math.log(this.start.value);\n this.target._logValue = Math.log(this.target.value);\n this.current._logValue = Math.log(this.current.value);\n }\n },\n\n /**\n * @function\n * @param {Number} target\n */\n springTo: function( target ) {\n $.console.assert(!this._exponential || target !== 0,\n \"[OpenSeadragon.Spring.springTo] target must be non-zero for exponential springs\");\n\n this.start.value = this.current.value;\n this.start.time = this.current.time;\n this.target.value = target;\n this.target.time = this.start.time + 1000 * this.animationTime;\n\n if (this._exponential) {\n this.start._logValue = Math.log(this.start.value);\n this.target._logValue = Math.log(this.target.value);\n }\n },\n\n /**\n * @function\n * @param {Number} delta\n */\n shiftBy: function( delta ) {\n this.start.value += delta;\n this.target.value += delta;\n\n if (this._exponential) {\n $.console.assert(this.target.value !== 0 && this.start.value !== 0,\n \"[OpenSeadragon.Spring.shiftBy] spring value must be non-zero for exponential springs\");\n\n this.start._logValue = Math.log(this.start.value);\n this.target._logValue = Math.log(this.target.value);\n }\n },\n\n setExponential: function(value) {\n this._exponential = value;\n\n if (this._exponential) {\n $.console.assert(this.current.value !== 0 && this.target.value !== 0 && this.start.value !== 0,\n \"[OpenSeadragon.Spring.setExponential] spring value must be non-zero for exponential springs\");\n\n this.start._logValue = Math.log(this.start.value);\n this.target._logValue = Math.log(this.target.value);\n this.current._logValue = Math.log(this.current.value);\n }\n },\n\n /**\n * @function\n * @returns true if the value got updated, false otherwise\n */\n update: function() {\n this.current.time = $.now();\n\n var startValue, targetValue;\n if (this._exponential) {\n startValue = this.start._logValue;\n targetValue = this.target._logValue;\n } else {\n startValue = this.start.value;\n targetValue = this.target.value;\n }\n\n var currentValue = (this.current.time >= this.target.time) ?\n targetValue :\n startValue +\n ( targetValue - startValue ) *\n transform(\n this.springStiffness,\n ( this.current.time - this.start.time ) /\n ( this.target.time - this.start.time )\n );\n\n var oldValue = this.current.value;\n if (this._exponential) {\n this.current.value = Math.exp(currentValue);\n } else {\n this.current.value = currentValue;\n }\n\n return oldValue != this.current.value;\n },\n\n /**\n * Returns whether the spring is at the target value\n * @function\n * @returns {Boolean} True if at target value, false otherwise\n */\n isAtTargetValue: function() {\n return this.current.value === this.target.value;\n }\n};\n\n/**\n * @private\n */\nfunction transform( stiffness, x ) {\n return ( 1.0 - Math.exp( stiffness * -x ) ) /\n ( 1.0 - Math.exp( -stiffness ) );\n}\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - ImageLoader\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function($){\n\n/**\n * @private\n * @class ImageJob\n * @classdesc Handles downloading of a single image.\n * @param {Object} options - Options for this ImageJob.\n * @param {String} [options.src] - URL of image to download.\n * @param {String} [options.loadWithAjax] - Whether to load this image with AJAX.\n * @param {String} [options.ajaxHeaders] - Headers to add to the image request if using AJAX.\n * @param {String} [options.crossOriginPolicy] - CORS policy to use for downloads\n * @param {Function} [options.callback] - Called once image has been downloaded.\n * @param {Function} [options.abort] - Called when this image job is aborted.\n * @param {Number} [options.timeout] - The max number of milliseconds that this image job may take to complete.\n */\nfunction ImageJob (options) {\n\n $.extend(true, this, {\n timeout: $.DEFAULT_SETTINGS.timeout,\n jobId: null\n }, options);\n\n /**\n * Image object which will contain downloaded image.\n * @member {Image} image\n * @memberof OpenSeadragon.ImageJob#\n */\n this.image = null;\n}\n\nImageJob.prototype = {\n errorMsg: null,\n\n /**\n * Starts the image job.\n * @method\n */\n start: function(){\n var self = this;\n var selfAbort = this.abort;\n\n this.image = new Image();\n\n this.image.onload = function(){\n self.finish(true);\n };\n this.image.onabort = this.image.onerror = function() {\n self.errorMsg = \"Image load aborted\";\n self.finish(false);\n };\n\n this.jobId = window.setTimeout(function(){\n self.errorMsg = \"Image load exceeded timeout\";\n self.finish(false);\n }, this.timeout);\n\n // Load the tile with an AJAX request if the loadWithAjax option is\n // set. Otherwise load the image by setting the source proprety of the image object.\n if (this.loadWithAjax) {\n this.request = $.makeAjaxRequest({\n url: this.src,\n withCredentials: this.ajaxWithCredentials,\n headers: this.ajaxHeaders,\n responseType: \"arraybuffer\",\n success: function(request) {\n var blb;\n // Make the raw data into a blob.\n // BlobBuilder fallback adapted from\n // http://stackoverflow.com/questions/15293694/blob-constructor-browser-compatibility\n try {\n blb = new window.Blob([request.response]);\n } catch (e) {\n var BlobBuilder = (\n window.BlobBuilder ||\n window.WebKitBlobBuilder ||\n window.MozBlobBuilder ||\n window.MSBlobBuilder\n );\n if (e.name === 'TypeError' && BlobBuilder) {\n var bb = new BlobBuilder();\n bb.append(request.response);\n blb = bb.getBlob();\n }\n }\n // If the blob is empty for some reason consider the image load a failure.\n if (blb.size === 0) {\n self.errorMsg = \"Empty image response.\";\n self.finish(false);\n }\n // Create a URL for the blob data and make it the source of the image object.\n // This will still trigger Image.onload to indicate a successful tile load.\n var url = (window.URL || window.webkitURL).createObjectURL(blb);\n self.image.src = url;\n },\n error: function(request) {\n self.errorMsg = \"Image load aborted - XHR error\";\n self.finish(false);\n }\n });\n\n // Provide a function to properly abort the request.\n this.abort = function() {\n self.request.abort();\n\n // Call the existing abort function if available\n if (typeof selfAbort === \"function\") {\n selfAbort();\n }\n };\n } else {\n if (this.crossOriginPolicy !== false) {\n this.image.crossOrigin = this.crossOriginPolicy;\n }\n\n this.image.src = this.src;\n }\n },\n\n finish: function(successful) {\n this.image.onload = this.image.onerror = this.image.onabort = null;\n if (!successful) {\n this.image = null;\n }\n\n if (this.jobId) {\n window.clearTimeout(this.jobId);\n }\n\n this.callback(this);\n }\n\n};\n\n/**\n * @class ImageLoader\n * @memberof OpenSeadragon\n * @classdesc Handles downloading of a set of images using asynchronous queue pattern.\n * You generally won't have to interact with the ImageLoader directly.\n * @param {Object} options - Options for this ImageLoader.\n * @param {Number} [options.jobLimit] - The number of concurrent image requests. See imageLoaderLimit in {@link OpenSeadragon.Options} for details.\n * @param {Number} [options.timeout] - The max number of milliseconds that an image job may take to complete.\n */\n$.ImageLoader = function(options) {\n\n $.extend(true, this, {\n jobLimit: $.DEFAULT_SETTINGS.imageLoaderLimit,\n timeout: $.DEFAULT_SETTINGS.timeout,\n jobQueue: [],\n jobsInProgress: 0\n }, options);\n\n};\n\n/** @lends OpenSeadragon.ImageLoader.prototype */\n$.ImageLoader.prototype = {\n\n /**\n * Add an unloaded image to the loader queue.\n * @method\n * @param {Object} options - Options for this job.\n * @param {String} [options.src] - URL of image to download.\n * @param {String} [options.loadWithAjax] - Whether to load this image with AJAX.\n * @param {String} [options.ajaxHeaders] - Headers to add to the image request if using AJAX.\n * @param {String|Boolean} [options.crossOriginPolicy] - CORS policy to use for downloads\n * @param {Boolean} [options.ajaxWithCredentials] - Whether to set withCredentials on AJAX\n * requests.\n * @param {Function} [options.callback] - Called once image has been downloaded.\n * @param {Function} [options.abort] - Called when this image job is aborted.\n */\n addJob: function(options) {\n var _this = this,\n complete = function(job) {\n completeJob(_this, job, options.callback);\n },\n jobOptions = {\n src: options.src,\n loadWithAjax: options.loadWithAjax,\n ajaxHeaders: options.loadWithAjax ? options.ajaxHeaders : null,\n crossOriginPolicy: options.crossOriginPolicy,\n ajaxWithCredentials: options.ajaxWithCredentials,\n callback: complete,\n abort: options.abort,\n timeout: this.timeout\n },\n newJob = new ImageJob(jobOptions);\n\n if ( !this.jobLimit || this.jobsInProgress < this.jobLimit ) {\n newJob.start();\n this.jobsInProgress++;\n }\n else {\n this.jobQueue.push( newJob );\n }\n },\n\n /**\n * Clear any unstarted image loading jobs from the queue.\n * @method\n */\n clear: function() {\n for( var i = 0; i < this.jobQueue.length; i++ ) {\n var job = this.jobQueue[i];\n if ( typeof job.abort === \"function\" ) {\n job.abort();\n }\n }\n\n this.jobQueue = [];\n }\n};\n\n/**\n * Cleans up ImageJob once completed.\n * @method\n * @private\n * @param loader - ImageLoader used to start job.\n * @param job - The ImageJob that has completed.\n * @param callback - Called once cleanup is finished.\n */\nfunction completeJob(loader, job, callback) {\n var nextJob;\n\n loader.jobsInProgress--;\n\n if ((!loader.jobLimit || loader.jobsInProgress < loader.jobLimit) && loader.jobQueue.length > 0) {\n nextJob = loader.jobQueue.shift();\n nextJob.start();\n loader.jobsInProgress++;\n }\n\n callback(job.image, job.errorMsg, job.request);\n}\n\n}(OpenSeadragon));\n","/*\n * OpenSeadragon - Tile\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class Tile\n * @memberof OpenSeadragon\n * @param {Number} level The zoom level this tile belongs to.\n * @param {Number} x The vector component 'x'.\n * @param {Number} y The vector component 'y'.\n * @param {OpenSeadragon.Point} bounds Where this tile fits, in normalized\n * coordinates.\n * @param {Boolean} exists Is this tile a part of a sparse image? ( Also has\n * this tile failed to load? )\n * @param {String} url The URL of this tile's image.\n * @param {CanvasRenderingContext2D} context2D The context2D of this tile if it\n * is provided directly by the tile source.\n * @param {Boolean} loadWithAjax Whether this tile image should be loaded with an AJAX request .\n * @param {Object} ajaxHeaders The headers to send with this tile's AJAX request (if applicable).\n */\n$.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, ajaxHeaders) {\n /**\n * The zoom level this tile belongs to.\n * @member {Number} level\n * @memberof OpenSeadragon.Tile#\n */\n this.level = level;\n /**\n * The vector component 'x'.\n * @member {Number} x\n * @memberof OpenSeadragon.Tile#\n */\n this.x = x;\n /**\n * The vector component 'y'.\n * @member {Number} y\n * @memberof OpenSeadragon.Tile#\n */\n this.y = y;\n /**\n * Where this tile fits, in normalized coordinates\n * @member {OpenSeadragon.Rect} bounds\n * @memberof OpenSeadragon.Tile#\n */\n this.bounds = bounds;\n /**\n * Is this tile a part of a sparse image? Also has this tile failed to load?\n * @member {Boolean} exists\n * @memberof OpenSeadragon.Tile#\n */\n this.exists = exists;\n /**\n * The URL of this tile's image.\n * @member {String} url\n * @memberof OpenSeadragon.Tile#\n */\n this.url = url;\n /**\n * The context2D of this tile if it is provided directly by the tile source.\n * @member {CanvasRenderingContext2D} context2D\n * @memberOf OpenSeadragon.Tile#\n */\n this.context2D = context2D;\n /**\n * Whether to load this tile's image with an AJAX request.\n * @member {Boolean} loadWithAjax\n * @memberof OpenSeadragon.Tile#\n */\n this.loadWithAjax = loadWithAjax;\n /**\n * The headers to be used in requesting this tile's image.\n * Only used if loadWithAjax is set to true.\n * @member {Object} ajaxHeaders\n * @memberof OpenSeadragon.Tile#\n */\n this.ajaxHeaders = ajaxHeaders;\n /**\n * The unique cache key for this tile.\n * @member {String} cacheKey\n * @memberof OpenSeadragon.Tile#\n */\n if (this.ajaxHeaders) {\n this.cacheKey = this.url + \"+\" + JSON.stringify(this.ajaxHeaders);\n } else {\n this.cacheKey = this.url;\n }\n /**\n * Is this tile loaded?\n * @member {Boolean} loaded\n * @memberof OpenSeadragon.Tile#\n */\n this.loaded = false;\n /**\n * Is this tile loading?\n * @member {Boolean} loading\n * @memberof OpenSeadragon.Tile#\n */\n this.loading = false;\n\n /**\n * The HTML div element for this tile\n * @member {Element} element\n * @memberof OpenSeadragon.Tile#\n */\n this.element = null;\n /**\n * The HTML img element for this tile.\n * @member {Element} imgElement\n * @memberof OpenSeadragon.Tile#\n */\n this.imgElement = null;\n /**\n * The Image object for this tile.\n * @member {Object} image\n * @memberof OpenSeadragon.Tile#\n */\n this.image = null;\n\n /**\n * The alias of this.element.style.\n * @member {String} style\n * @memberof OpenSeadragon.Tile#\n */\n this.style = null;\n /**\n * This tile's position on screen, in pixels.\n * @member {OpenSeadragon.Point} position\n * @memberof OpenSeadragon.Tile#\n */\n this.position = null;\n /**\n * This tile's size on screen, in pixels.\n * @member {OpenSeadragon.Point} size\n * @memberof OpenSeadragon.Tile#\n */\n this.size = null;\n /**\n * The start time of this tile's blending.\n * @member {Number} blendStart\n * @memberof OpenSeadragon.Tile#\n */\n this.blendStart = null;\n /**\n * The current opacity this tile should be.\n * @member {Number} opacity\n * @memberof OpenSeadragon.Tile#\n */\n this.opacity = null;\n /**\n * The squared distance of this tile to the viewport center.\n * Use for comparing tiles.\n * @private\n * @member {Number} squaredDistance\n * @memberof OpenSeadragon.Tile#\n */\n this.squaredDistance = null;\n /**\n * The visibility score of this tile.\n * @member {Number} visibility\n * @memberof OpenSeadragon.Tile#\n */\n this.visibility = null;\n\n /**\n * Whether this tile is currently being drawn.\n * @member {Boolean} beingDrawn\n * @memberof OpenSeadragon.Tile#\n */\n this.beingDrawn = false;\n\n /**\n * Timestamp the tile was last touched.\n * @member {Number} lastTouchTime\n * @memberof OpenSeadragon.Tile#\n */\n this.lastTouchTime = 0;\n\n /**\n * Whether this tile is in the right-most column for its level.\n * @member {Boolean} isRightMost\n * @memberof OpenSeadragon.Tile#\n */\n this.isRightMost = false;\n\n /**\n * Whether this tile is in the bottom-most row for its level.\n * @member {Boolean} isBottomMost\n * @memberof OpenSeadragon.Tile#\n */\n this.isBottomMost = false;\n};\n\n/** @lends OpenSeadragon.Tile.prototype */\n$.Tile.prototype = {\n\n /**\n * Provides a string representation of this tiles level and (x,y)\n * components.\n * @function\n * @returns {String}\n */\n toString: function() {\n return this.level + \"/\" + this.x + \"_\" + this.y;\n },\n\n // private\n _hasTransparencyChannel: function() {\n return !!this.context2D || this.url.match('.png');\n },\n\n /**\n * Renders the tile in an html container.\n * @function\n * @param {Element} container\n */\n drawHTML: function( container ) {\n if (!this.cacheImageRecord) {\n $.console.warn(\n '[Tile.drawHTML] attempting to draw tile %s when it\\'s not cached',\n this.toString());\n return;\n }\n\n if ( !this.loaded ) {\n $.console.warn(\n \"Attempting to draw tile %s when it's not yet loaded.\",\n this.toString()\n );\n return;\n }\n\n //EXPERIMENTAL - trying to figure out how to scale the container\n // content during animation of the container size.\n\n if ( !this.element ) {\n this.element = $.makeNeutralElement( \"div\" );\n this.imgElement = this.cacheImageRecord.getImage().cloneNode();\n this.imgElement.style.msInterpolationMode = \"nearest-neighbor\";\n this.imgElement.style.width = \"100%\";\n this.imgElement.style.height = \"100%\";\n\n this.style = this.element.style;\n this.style.position = \"absolute\";\n }\n if ( this.element.parentNode != container ) {\n container.appendChild( this.element );\n }\n if ( this.imgElement.parentNode != this.element ) {\n this.element.appendChild( this.imgElement );\n }\n\n this.style.top = this.position.y + \"px\";\n this.style.left = this.position.x + \"px\";\n this.style.height = this.size.y + \"px\";\n this.style.width = this.size.x + \"px\";\n\n $.setElementOpacity( this.element, this.opacity );\n },\n\n /**\n * Renders the tile in a canvas-based context.\n * @function\n * @param {Canvas} context\n * @param {Function} drawingHandler - Method for firing the drawing event.\n * drawingHandler({context, tile, rendered})\n * where rendered is the context with the pre-drawn image.\n * @param {Number} [scale=1] - Apply a scale to position and size\n * @param {OpenSeadragon.Point} [translate] - A translation vector\n */\n drawCanvas: function( context, drawingHandler, scale, translate ) {\n\n var position = this.position.times($.pixelDensityRatio),\n size = this.size.times($.pixelDensityRatio),\n rendered;\n\n if (!this.context2D && !this.cacheImageRecord) {\n $.console.warn(\n '[Tile.drawCanvas] attempting to draw tile %s when it\\'s not cached',\n this.toString());\n return;\n }\n\n rendered = this.context2D || this.cacheImageRecord.getRenderedContext();\n\n if ( !this.loaded || !rendered ){\n $.console.warn(\n \"Attempting to draw tile %s when it's not yet loaded.\",\n this.toString()\n );\n\n return;\n }\n\n context.save();\n\n context.globalAlpha = this.opacity;\n\n if (typeof scale === 'number' && scale !== 1) {\n // draw tile at a different scale\n position = position.times(scale);\n size = size.times(scale);\n }\n\n if (translate instanceof $.Point) {\n // shift tile position slightly\n position = position.plus(translate);\n }\n\n //if we are supposed to be rendering fully opaque rectangle,\n //ie its done fading or fading is turned off, and if we are drawing\n //an image with an alpha channel, then the only way\n //to avoid seeing the tile underneath is to clear the rectangle\n if (context.globalAlpha === 1 && this._hasTransparencyChannel()) {\n //clearing only the inside of the rectangle occupied\n //by the png prevents edge flikering\n context.clearRect(\n position.x + 1,\n position.y + 1,\n size.x - 2,\n size.y - 2\n );\n }\n\n // This gives the application a chance to make image manipulation\n // changes as we are rendering the image\n drawingHandler({context: context, tile: this, rendered: rendered});\n\n context.drawImage(\n rendered.canvas,\n 0,\n 0,\n rendered.canvas.width,\n rendered.canvas.height,\n position.x,\n position.y,\n size.x,\n size.y\n );\n\n context.restore();\n },\n\n /**\n * Get the ratio between current and original size.\n * @function\n * @return {Float}\n */\n getScaleForEdgeSmoothing: function() {\n var context;\n if (this.cacheImageRecord) {\n context = this.cacheImageRecord.getRenderedContext();\n } else if (this.context2D) {\n context = this.context2D;\n } else {\n $.console.warn(\n '[Tile.drawCanvas] attempting to get tile scale %s when tile\\'s not cached',\n this.toString());\n return 1;\n }\n return context.canvas.width / (this.size.x * $.pixelDensityRatio);\n },\n\n /**\n * Get a translation vector that when applied to the tile position produces integer coordinates.\n * Needed to avoid swimming and twitching.\n * @function\n * @param {Number} [scale=1] - Scale to be applied to position.\n * @return {OpenSeadragon.Point}\n */\n getTranslationForEdgeSmoothing: function(scale, canvasSize, sketchCanvasSize) {\n // The translation vector must have positive values, otherwise the image goes a bit off\n // the sketch canvas to the top and left and we must use negative coordinates to repaint it\n // to the main canvas. In that case, some browsers throw:\n // INDEX_SIZE_ERR: DOM Exception 1: Index or size was negative, or greater than the allowed value.\n var x = Math.max(1, Math.ceil((sketchCanvasSize.x - canvasSize.x) / 2));\n var y = Math.max(1, Math.ceil((sketchCanvasSize.y - canvasSize.y) / 2));\n return new $.Point(x, y).minus(\n this.position\n .times($.pixelDensityRatio)\n .times(scale || 1)\n .apply(function(x) {\n return x % 1;\n })\n );\n },\n\n /**\n * Removes tile from its container.\n * @function\n */\n unload: function() {\n if ( this.imgElement && this.imgElement.parentNode ) {\n this.imgElement.parentNode.removeChild( this.imgElement );\n }\n if ( this.element && this.element.parentNode ) {\n this.element.parentNode.removeChild( this.element );\n }\n\n this.element = null;\n this.imgElement = null;\n this.loaded = false;\n this.loading = false;\n }\n};\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - Overlay\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function($) {\n\n /**\n * An enumeration of positions that an overlay may be assigned relative to\n * the viewport.\n * It is identical to OpenSeadragon.Placement but is kept for backward\n * compatibility.\n * @member OverlayPlacement\n * @memberof OpenSeadragon\n * @see OpenSeadragon.Placement\n * @static\n * @readonly\n * @type {Object}\n * @property {Number} CENTER\n * @property {Number} TOP_LEFT\n * @property {Number} TOP\n * @property {Number} TOP_RIGHT\n * @property {Number} RIGHT\n * @property {Number} BOTTOM_RIGHT\n * @property {Number} BOTTOM\n * @property {Number} BOTTOM_LEFT\n * @property {Number} LEFT\n */\n $.OverlayPlacement = $.Placement;\n\n /**\n * An enumeration of possible ways to handle overlays rotation\n * @member OverlayRotationMode\n * @memberOf OpenSeadragon\n * @static\n * @readonly\n * @property {Number} NO_ROTATION The overlay ignore the viewport rotation.\n * @property {Number} EXACT The overlay use CSS 3 transforms to rotate with\n * the viewport. If the overlay contains text, it will get rotated as well.\n * @property {Number} BOUNDING_BOX The overlay adjusts for rotation by\n * taking the size of the bounding box of the rotated bounds.\n * Only valid for overlays with Rect location and scalable in both directions.\n */\n $.OverlayRotationMode = $.freezeObject({\n NO_ROTATION: 1,\n EXACT: 2,\n BOUNDING_BOX: 3\n });\n\n /**\n * @class Overlay\n * @classdesc Provides a way to float an HTML element on top of the viewer element.\n *\n * @memberof OpenSeadragon\n * @param {Object} options\n * @param {Element} options.element\n * @param {OpenSeadragon.Point|OpenSeadragon.Rect} options.location - The\n * location of the overlay on the image. If a {@link OpenSeadragon.Point}\n * is specified, the overlay will be located at this location with respect\n * to the placement option. If a {@link OpenSeadragon.Rect} is specified,\n * the overlay will be placed at this location with the corresponding width\n * and height and placement TOP_LEFT.\n * @param {OpenSeadragon.Placement} [options.placement=OpenSeadragon.Placement.TOP_LEFT]\n * Defines what part of the overlay should be at the specified options.location\n * @param {OpenSeadragon.Overlay.OnDrawCallback} [options.onDraw]\n * @param {Boolean} [options.checkResize=true] Set to false to avoid to\n * check the size of the overlay everytime it is drawn in the directions\n * which are not scaled. It will improve performances but will cause a\n * misalignment if the overlay size changes.\n * @param {Number} [options.width] The width of the overlay in viewport\n * coordinates. If specified, the width of the overlay will be adjusted when\n * the zoom changes.\n * @param {Number} [options.height] The height of the overlay in viewport\n * coordinates. If specified, the height of the overlay will be adjusted when\n * the zoom changes.\n * @param {Boolean} [options.rotationMode=OpenSeadragon.OverlayRotationMode.EXACT]\n * How to handle the rotation of the viewport.\n */\n $.Overlay = function(element, location, placement) {\n\n /**\n * onDraw callback signature used by {@link OpenSeadragon.Overlay}.\n *\n * @callback OnDrawCallback\n * @memberof OpenSeadragon.Overlay\n * @param {OpenSeadragon.Point} position\n * @param {OpenSeadragon.Point} size\n * @param {Element} element\n */\n\n var options;\n if ($.isPlainObject(element)) {\n options = element;\n } else {\n options = {\n element: element,\n location: location,\n placement: placement\n };\n }\n\n this.element = options.element;\n this.style = options.element.style;\n this._init(options);\n };\n\n /** @lends OpenSeadragon.Overlay.prototype */\n $.Overlay.prototype = {\n\n // private\n _init: function(options) {\n this.location = options.location;\n this.placement = options.placement === undefined ?\n $.Placement.TOP_LEFT : options.placement;\n this.onDraw = options.onDraw;\n this.checkResize = options.checkResize === undefined ?\n true : options.checkResize;\n\n // When this.width is not null, the overlay get scaled horizontally\n this.width = options.width === undefined ? null : options.width;\n\n // When this.height is not null, the overlay get scaled vertically\n this.height = options.height === undefined ? null : options.height;\n\n this.rotationMode = options.rotationMode || $.OverlayRotationMode.EXACT;\n\n // Having a rect as location is a syntactic sugar\n if (this.location instanceof $.Rect) {\n this.width = this.location.width;\n this.height = this.location.height;\n this.location = this.location.getTopLeft();\n this.placement = $.Placement.TOP_LEFT;\n }\n\n // Deprecated properties kept for backward compatibility.\n this.scales = this.width !== null && this.height !== null;\n this.bounds = new $.Rect(\n this.location.x, this.location.y, this.width, this.height);\n this.position = this.location;\n },\n\n /**\n * Internal function to adjust the position of an overlay\n * depending on it size and placement.\n * @function\n * @param {OpenSeadragon.Point} position\n * @param {OpenSeadragon.Point} size\n */\n adjust: function(position, size) {\n var properties = $.Placement.properties[this.placement];\n if (!properties) {\n return;\n }\n if (properties.isHorizontallyCentered) {\n position.x -= size.x / 2;\n } else if (properties.isRight) {\n position.x -= size.x;\n }\n if (properties.isVerticallyCentered) {\n position.y -= size.y / 2;\n } else if (properties.isBottom) {\n position.y -= size.y;\n }\n },\n\n /**\n * @function\n */\n destroy: function() {\n var element = this.element;\n var style = this.style;\n\n if (element.parentNode) {\n element.parentNode.removeChild(element);\n //this should allow us to preserve overlays when required between\n //pages\n if (element.prevElementParent) {\n style.display = 'none';\n //element.prevElementParent.insertBefore(\n // element,\n // element.prevNextSibling\n //);\n document.body.appendChild(element);\n }\n }\n\n // clear the onDraw callback\n this.onDraw = null;\n\n style.top = \"\";\n style.left = \"\";\n style.position = \"\";\n\n if (this.width !== null) {\n style.width = \"\";\n }\n if (this.height !== null) {\n style.height = \"\";\n }\n var transformOriginProp = $.getCssPropertyWithVendorPrefix(\n 'transformOrigin');\n var transformProp = $.getCssPropertyWithVendorPrefix(\n 'transform');\n if (transformOriginProp && transformProp) {\n style[transformOriginProp] = \"\";\n style[transformProp] = \"\";\n }\n },\n\n /**\n * @function\n * @param {Element} container\n */\n drawHTML: function(container, viewport) {\n var element = this.element;\n if (element.parentNode !== container) {\n //save the source parent for later if we need it\n element.prevElementParent = element.parentNode;\n element.prevNextSibling = element.nextSibling;\n container.appendChild(element);\n\n // have to set position before calculating size, fix #1116\n this.style.position = \"absolute\";\n // this.size is used by overlays which don't get scaled in at\n // least one direction when this.checkResize is set to false.\n this.size = $.getElementSize(element);\n }\n\n var positionAndSize = this._getOverlayPositionAndSize(viewport);\n\n var position = positionAndSize.position;\n var size = this.size = positionAndSize.size;\n var rotate = positionAndSize.rotate;\n\n // call the onDraw callback if it exists to allow one to overwrite\n // the drawing/positioning/sizing of the overlay\n if (this.onDraw) {\n this.onDraw(position, size, this.element);\n } else {\n var style = this.style;\n style.left = position.x + \"px\";\n style.top = position.y + \"px\";\n if (this.width !== null) {\n style.width = size.x + \"px\";\n }\n if (this.height !== null) {\n style.height = size.y + \"px\";\n }\n var transformOriginProp = $.getCssPropertyWithVendorPrefix(\n 'transformOrigin');\n var transformProp = $.getCssPropertyWithVendorPrefix(\n 'transform');\n if (transformOriginProp && transformProp) {\n if (rotate) {\n style[transformOriginProp] = this._getTransformOrigin();\n style[transformProp] = \"rotate(\" + rotate + \"deg)\";\n } else {\n style[transformOriginProp] = \"\";\n style[transformProp] = \"\";\n }\n }\n\n if (style.display !== 'none') {\n style.display = 'block';\n }\n }\n },\n\n // private\n _getOverlayPositionAndSize: function(viewport) {\n var position = viewport.pixelFromPoint(this.location, true);\n var size = this._getSizeInPixels(viewport);\n this.adjust(position, size);\n\n var rotate = 0;\n if (viewport.degrees &&\n this.rotationMode !== $.OverlayRotationMode.NO_ROTATION) {\n // BOUNDING_BOX is only valid if both directions get scaled.\n // Get replaced by EXACT otherwise.\n if (this.rotationMode === $.OverlayRotationMode.BOUNDING_BOX &&\n this.width !== null && this.height !== null) {\n var rect = new $.Rect(position.x, position.y, size.x, size.y);\n var boundingBox = this._getBoundingBox(rect, viewport.degrees);\n position = boundingBox.getTopLeft();\n size = boundingBox.getSize();\n } else {\n rotate = viewport.degrees;\n }\n }\n\n return {\n position: position,\n size: size,\n rotate: rotate\n };\n },\n\n // private\n _getSizeInPixels: function(viewport) {\n var width = this.size.x;\n var height = this.size.y;\n if (this.width !== null || this.height !== null) {\n var scaledSize = viewport.deltaPixelsFromPointsNoRotate(\n new $.Point(this.width || 0, this.height || 0), true);\n if (this.width !== null) {\n width = scaledSize.x;\n }\n if (this.height !== null) {\n height = scaledSize.y;\n }\n }\n if (this.checkResize &&\n (this.width === null || this.height === null)) {\n var eltSize = this.size = $.getElementSize(this.element);\n if (this.width === null) {\n width = eltSize.x;\n }\n if (this.height === null) {\n height = eltSize.y;\n }\n }\n return new $.Point(width, height);\n },\n\n // private\n _getBoundingBox: function(rect, degrees) {\n var refPoint = this._getPlacementPoint(rect);\n return rect.rotate(degrees, refPoint).getBoundingBox();\n },\n\n // private\n _getPlacementPoint: function(rect) {\n var result = new $.Point(rect.x, rect.y);\n var properties = $.Placement.properties[this.placement];\n if (properties) {\n if (properties.isHorizontallyCentered) {\n result.x += rect.width / 2;\n } else if (properties.isRight) {\n result.x += rect.width;\n }\n if (properties.isVerticallyCentered) {\n result.y += rect.height / 2;\n } else if (properties.isBottom) {\n result.y += rect.height;\n }\n }\n return result;\n },\n\n // private\n _getTransformOrigin: function() {\n var result = \"\";\n var properties = $.Placement.properties[this.placement];\n if (!properties) {\n return result;\n }\n if (properties.isLeft) {\n result = \"left\";\n } else if (properties.isRight) {\n result = \"right\";\n }\n if (properties.isTop) {\n result += \" top\";\n } else if (properties.isBottom) {\n result += \" bottom\";\n }\n return result;\n },\n\n /**\n * Changes the overlay settings.\n * @function\n * @param {OpenSeadragon.Point|OpenSeadragon.Rect|Object} location\n * If an object is specified, the options are the same than the constructor\n * except for the element which can not be changed.\n * @param {OpenSeadragon.Placement} placement\n */\n update: function(location, placement) {\n var options = $.isPlainObject(location) ? location : {\n location: location,\n placement: placement\n };\n this._init({\n location: options.location || this.location,\n placement: options.placement !== undefined ?\n options.placement : this.placement,\n onDraw: options.onDraw || this.onDraw,\n checkResize: options.checkResize || this.checkResize,\n width: options.width !== undefined ? options.width : this.width,\n height: options.height !== undefined ? options.height : this.height,\n rotationMode: options.rotationMode || this.rotationMode\n });\n },\n\n /**\n * Returns the current bounds of the overlay in viewport coordinates\n * @function\n * @param {OpenSeadragon.Viewport} viewport the viewport\n * @returns {OpenSeadragon.Rect} overlay bounds\n */\n getBounds: function(viewport) {\n $.console.assert(viewport,\n 'A viewport must now be passed to Overlay.getBounds.');\n var width = this.width;\n var height = this.height;\n if (width === null || height === null) {\n var size = viewport.deltaPointsFromPixelsNoRotate(this.size, true);\n if (width === null) {\n width = size.x;\n }\n if (height === null) {\n height = size.y;\n }\n }\n var location = this.location.clone();\n this.adjust(location, new $.Point(width, height));\n return this._adjustBoundsForRotation(\n viewport, new $.Rect(location.x, location.y, width, height));\n },\n\n // private\n _adjustBoundsForRotation: function(viewport, bounds) {\n if (!viewport ||\n viewport.degrees === 0 ||\n this.rotationMode === $.OverlayRotationMode.EXACT) {\n return bounds;\n }\n if (this.rotationMode === $.OverlayRotationMode.BOUNDING_BOX) {\n // If overlay not fully scalable, BOUNDING_BOX falls back to EXACT\n if (this.width === null || this.height === null) {\n return bounds;\n }\n // It is easier to just compute the position and size and\n // convert to viewport coordinates.\n var positionAndSize = this._getOverlayPositionAndSize(viewport);\n return viewport.viewerElementToViewportRectangle(new $.Rect(\n positionAndSize.position.x,\n positionAndSize.position.y,\n positionAndSize.size.x,\n positionAndSize.size.y));\n }\n\n // NO_ROTATION case\n return bounds.rotate(-viewport.degrees,\n this._getPlacementPoint(bounds));\n }\n };\n\n}(OpenSeadragon));\n","/*\n * OpenSeadragon - Drawer\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class Drawer\n * @memberof OpenSeadragon\n * @classdesc Handles rendering of tiles for an {@link OpenSeadragon.Viewer}.\n * @param {Object} options - Options for this Drawer.\n * @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this Drawer.\n * @param {OpenSeadragon.Viewport} options.viewport - Reference to Viewer viewport.\n * @param {Element} options.element - Parent element.\n * @param {Number} [options.debugGridColor] - See debugGridColor in {@link OpenSeadragon.Options} for details.\n */\n$.Drawer = function( options ) {\n\n $.console.assert( options.viewer, \"[Drawer] options.viewer is required\" );\n\n //backward compatibility for positional args while prefering more\n //idiomatic javascript options object as the only argument\n var args = arguments;\n\n if( !$.isPlainObject( options ) ){\n options = {\n source: args[ 0 ], // Reference to Viewer tile source.\n viewport: args[ 1 ], // Reference to Viewer viewport.\n element: args[ 2 ] // Parent element.\n };\n }\n\n $.console.assert( options.viewport, \"[Drawer] options.viewport is required\" );\n $.console.assert( options.element, \"[Drawer] options.element is required\" );\n\n if ( options.source ) {\n $.console.error( \"[Drawer] options.source is no longer accepted; use TiledImage instead\" );\n }\n\n this.viewer = options.viewer;\n this.viewport = options.viewport;\n this.debugGridColor = typeof options.debugGridColor === 'string' ? [options.debugGridColor] : options.debugGridColor || $.DEFAULT_SETTINGS.debugGridColor;\n if (options.opacity) {\n $.console.error( \"[Drawer] options.opacity is no longer accepted; set the opacity on the TiledImage instead\" );\n }\n\n this.useCanvas = $.supportsCanvas && ( this.viewer ? this.viewer.useCanvas : true );\n /**\n * The parent element of this Drawer instance, passed in when the Drawer was created.\n * The parent of {@link OpenSeadragon.Drawer#canvas}.\n * @member {Element} container\n * @memberof OpenSeadragon.Drawer#\n */\n this.container = $.getElement( options.element );\n /**\n * A <canvas> element if the browser supports them, otherwise a <div> element.\n * Child element of {@link OpenSeadragon.Drawer#container}.\n * @member {Element} canvas\n * @memberof OpenSeadragon.Drawer#\n */\n this.canvas = $.makeNeutralElement( this.useCanvas ? \"canvas\" : \"div\" );\n /**\n * 2d drawing context for {@link OpenSeadragon.Drawer#canvas} if it's a <canvas> element, otherwise null.\n * @member {Object} context\n * @memberof OpenSeadragon.Drawer#\n */\n this.context = this.useCanvas ? this.canvas.getContext( \"2d\" ) : null;\n\n /**\n * Sketch canvas used to temporarily draw tiles which cannot be drawn directly\n * to the main canvas due to opacity. Lazily initialized.\n */\n this.sketchCanvas = null;\n this.sketchContext = null;\n\n /**\n * @member {Element} element\n * @memberof OpenSeadragon.Drawer#\n * @deprecated Alias for {@link OpenSeadragon.Drawer#container}.\n */\n this.element = this.container;\n\n // We force our container to ltr because our drawing math doesn't work in rtl.\n // This issue only affects our canvas renderer, but we do it always for consistency.\n // Note that this means overlays you want to be rtl need to be explicitly set to rtl.\n this.container.dir = 'ltr';\n\n // check canvas available width and height, set canvas width and height such that the canvas backing store is set to the proper pixel density\n if (this.useCanvas) {\n var viewportSize = this._calculateCanvasSize();\n this.canvas.width = viewportSize.x;\n this.canvas.height = viewportSize.y;\n }\n\n this.canvas.style.width = \"100%\";\n this.canvas.style.height = \"100%\";\n this.canvas.style.position = \"absolute\";\n $.setElementOpacity( this.canvas, this.opacity, true );\n\n // explicit left-align\n this.container.style.textAlign = \"left\";\n this.container.appendChild( this.canvas );\n};\n\n/** @lends OpenSeadragon.Drawer.prototype */\n$.Drawer.prototype = {\n // deprecated\n addOverlay: function( element, location, placement, onDraw ) {\n $.console.error(\"drawer.addOverlay is deprecated. Use viewer.addOverlay instead.\");\n this.viewer.addOverlay( element, location, placement, onDraw );\n return this;\n },\n\n // deprecated\n updateOverlay: function( element, location, placement ) {\n $.console.error(\"drawer.updateOverlay is deprecated. Use viewer.updateOverlay instead.\");\n this.viewer.updateOverlay( element, location, placement );\n return this;\n },\n\n // deprecated\n removeOverlay: function( element ) {\n $.console.error(\"drawer.removeOverlay is deprecated. Use viewer.removeOverlay instead.\");\n this.viewer.removeOverlay( element );\n return this;\n },\n\n // deprecated\n clearOverlays: function() {\n $.console.error(\"drawer.clearOverlays is deprecated. Use viewer.clearOverlays instead.\");\n this.viewer.clearOverlays();\n return this;\n },\n\n /**\n * Set the opacity of the drawer.\n * @param {Number} opacity\n * @return {OpenSeadragon.Drawer} Chainable.\n */\n setOpacity: function( opacity ) {\n $.console.error(\"drawer.setOpacity is deprecated. Use tiledImage.setOpacity instead.\");\n var world = this.viewer.world;\n for (var i = 0; i < world.getItemCount(); i++) {\n world.getItemAt( i ).setOpacity( opacity );\n }\n return this;\n },\n\n /**\n * Get the opacity of the drawer.\n * @returns {Number}\n */\n getOpacity: function() {\n $.console.error(\"drawer.getOpacity is deprecated. Use tiledImage.getOpacity instead.\");\n var world = this.viewer.world;\n var maxOpacity = 0;\n for (var i = 0; i < world.getItemCount(); i++) {\n var opacity = world.getItemAt( i ).getOpacity();\n if ( opacity > maxOpacity ) {\n maxOpacity = opacity;\n }\n }\n return maxOpacity;\n },\n\n // deprecated\n needsUpdate: function() {\n $.console.error( \"[Drawer.needsUpdate] this function is deprecated. Use World.needsDraw instead.\" );\n return this.viewer.world.needsDraw();\n },\n\n // deprecated\n numTilesLoaded: function() {\n $.console.error( \"[Drawer.numTilesLoaded] this function is deprecated. Use TileCache.numTilesLoaded instead.\" );\n return this.viewer.tileCache.numTilesLoaded();\n },\n\n // deprecated\n reset: function() {\n $.console.error( \"[Drawer.reset] this function is deprecated. Use World.resetItems instead.\" );\n this.viewer.world.resetItems();\n return this;\n },\n\n // deprecated\n update: function() {\n $.console.error( \"[Drawer.update] this function is deprecated. Use Drawer.clear and World.draw instead.\" );\n this.clear();\n this.viewer.world.draw();\n return this;\n },\n\n /**\n * @return {Boolean} True if rotation is supported.\n */\n canRotate: function() {\n return this.useCanvas;\n },\n\n /**\n * Destroy the drawer (unload current loaded tiles)\n */\n destroy: function() {\n //force unloading of current canvas (1x1 will be gc later, trick not necessarily needed)\n this.canvas.width = 1;\n this.canvas.height = 1;\n this.sketchCanvas = null;\n this.sketchContext = null;\n },\n\n /**\n * Clears the Drawer so it's ready to draw another frame.\n */\n clear: function() {\n this.canvas.innerHTML = \"\";\n if ( this.useCanvas ) {\n var viewportSize = this._calculateCanvasSize();\n if( this.canvas.width != viewportSize.x ||\n this.canvas.height != viewportSize.y ) {\n this.canvas.width = viewportSize.x;\n this.canvas.height = viewportSize.y;\n if ( this.sketchCanvas !== null ) {\n var sketchCanvasSize = this._calculateSketchCanvasSize();\n this.sketchCanvas.width = sketchCanvasSize.x;\n this.sketchCanvas.height = sketchCanvasSize.y;\n }\n }\n this._clear();\n }\n },\n\n _clear: function (useSketch, bounds) {\n if (!this.useCanvas) {\n return;\n }\n var context = this._getContext(useSketch);\n if (bounds) {\n context.clearRect(bounds.x, bounds.y, bounds.width, bounds.height);\n } else {\n var canvas = context.canvas;\n context.clearRect(0, 0, canvas.width, canvas.height);\n }\n },\n\n /**\n * Scale from OpenSeadragon viewer rectangle to drawer rectangle\n * (ignoring rotation)\n * @param {OpenSeadragon.Rect} rectangle - The rectangle in viewport coordinate system.\n * @return {OpenSeadragon.Rect} Rectangle in drawer coordinate system.\n */\n viewportToDrawerRectangle: function(rectangle) {\n var topLeft = this.viewport.pixelFromPointNoRotate(rectangle.getTopLeft(), true);\n var size = this.viewport.deltaPixelsFromPointsNoRotate(rectangle.getSize(), true);\n\n return new $.Rect(\n topLeft.x * $.pixelDensityRatio,\n topLeft.y * $.pixelDensityRatio,\n size.x * $.pixelDensityRatio,\n size.y * $.pixelDensityRatio\n );\n },\n\n /**\n * Draws the given tile.\n * @param {OpenSeadragon.Tile} tile - The tile to draw.\n * @param {Function} drawingHandler - Method for firing the drawing event if using canvas.\n * drawingHandler({context, tile, rendered})\n * @param {Boolean} useSketch - Whether to use the sketch canvas or not.\n * where rendered is the context with the pre-drawn image.\n * @param {Float} [scale=1] - Apply a scale to tile position and size. Defaults to 1.\n * @param {OpenSeadragon.Point} [translate] A translation vector to offset tile position\n */\n drawTile: function(tile, drawingHandler, useSketch, scale, translate) {\n $.console.assert(tile, '[Drawer.drawTile] tile is required');\n $.console.assert(drawingHandler, '[Drawer.drawTile] drawingHandler is required');\n\n if (this.useCanvas) {\n var context = this._getContext(useSketch);\n scale = scale || 1;\n tile.drawCanvas(context, drawingHandler, scale, translate);\n } else {\n tile.drawHTML( this.canvas );\n }\n },\n\n _getContext: function( useSketch ) {\n var context = this.context;\n if ( useSketch ) {\n if (this.sketchCanvas === null) {\n this.sketchCanvas = document.createElement( \"canvas\" );\n var sketchCanvasSize = this._calculateSketchCanvasSize();\n this.sketchCanvas.width = sketchCanvasSize.x;\n this.sketchCanvas.height = sketchCanvasSize.y;\n this.sketchContext = this.sketchCanvas.getContext( \"2d\" );\n\n // If the viewport is not currently rotated, the sketchCanvas\n // will have the same size as the main canvas. However, if\n // the viewport get rotated later on, we will need to resize it.\n if (this.viewport.getRotation() === 0) {\n var self = this;\n this.viewer.addHandler('rotate', function resizeSketchCanvas() {\n if (self.viewport.getRotation() === 0) {\n return;\n }\n self.viewer.removeHandler('rotate', resizeSketchCanvas);\n var sketchCanvasSize = self._calculateSketchCanvasSize();\n self.sketchCanvas.width = sketchCanvasSize.x;\n self.sketchCanvas.height = sketchCanvasSize.y;\n });\n }\n }\n context = this.sketchContext;\n }\n return context;\n },\n\n // private\n saveContext: function( useSketch ) {\n if (!this.useCanvas) {\n return;\n }\n\n this._getContext( useSketch ).save();\n },\n\n // private\n restoreContext: function( useSketch ) {\n if (!this.useCanvas) {\n return;\n }\n\n this._getContext( useSketch ).restore();\n },\n\n // private\n setClip: function(rect, useSketch) {\n if (!this.useCanvas) {\n return;\n }\n\n var context = this._getContext( useSketch );\n context.beginPath();\n context.rect(rect.x, rect.y, rect.width, rect.height);\n context.clip();\n },\n\n // private\n drawRectangle: function(rect, fillStyle, useSketch) {\n if (!this.useCanvas) {\n return;\n }\n\n var context = this._getContext( useSketch );\n context.save();\n context.fillStyle = fillStyle;\n context.fillRect(rect.x, rect.y, rect.width, rect.height);\n context.restore();\n },\n\n /**\n * Blends the sketch canvas in the main canvas.\n * @param {Object} options The options\n * @param {Float} options.opacity The opacity of the blending.\n * @param {Float} [options.scale=1] The scale at which tiles were drawn on\n * the sketch. Default is 1.\n * Use scale to draw at a lower scale and then enlarge onto the main canvas.\n * @param {OpenSeadragon.Point} [options.translate] A translation vector\n * that was used to draw the tiles\n * @param {String} [options.compositeOperation] - How the image is\n * composited onto other images; see compositeOperation in\n * {@link OpenSeadragon.Options} for possible values.\n * @param {OpenSeadragon.Rect} [options.bounds] The part of the sketch\n * canvas to blend in the main canvas. If specified, options.scale and\n * options.translate get ignored.\n */\n blendSketch: function(opacity, scale, translate, compositeOperation) {\n var options = opacity;\n if (!$.isPlainObject(options)) {\n options = {\n opacity: opacity,\n scale: scale,\n translate: translate,\n compositeOperation: compositeOperation\n };\n }\n if (!this.useCanvas || !this.sketchCanvas) {\n return;\n }\n opacity = options.opacity;\n compositeOperation = options.compositeOperation;\n var bounds = options.bounds;\n\n this.context.save();\n this.context.globalAlpha = opacity;\n if (compositeOperation) {\n this.context.globalCompositeOperation = compositeOperation;\n }\n if (bounds) {\n // Internet Explorer, Microsoft Edge, and Safari have problems\n // when you call context.drawImage with negative x or y\n // or x + width or y + height greater than the canvas width or height respectively.\n if (bounds.x < 0) {\n bounds.width += bounds.x;\n bounds.x = 0;\n }\n if (bounds.x + bounds.width > this.canvas.width) {\n bounds.width = this.canvas.width - bounds.x;\n }\n if (bounds.y < 0) {\n bounds.height += bounds.y;\n bounds.y = 0;\n }\n if (bounds.y + bounds.height > this.canvas.height) {\n bounds.height = this.canvas.height - bounds.y;\n }\n\n this.context.drawImage(\n this.sketchCanvas,\n bounds.x,\n bounds.y,\n bounds.width,\n bounds.height,\n bounds.x,\n bounds.y,\n bounds.width,\n bounds.height\n );\n } else {\n scale = options.scale || 1;\n translate = options.translate;\n var position = translate instanceof $.Point ?\n translate : new $.Point(0, 0);\n\n var widthExt = 0;\n var heightExt = 0;\n if (translate) {\n var widthDiff = this.sketchCanvas.width - this.canvas.width;\n var heightDiff = this.sketchCanvas.height - this.canvas.height;\n widthExt = Math.round(widthDiff / 2);\n heightExt = Math.round(heightDiff / 2);\n }\n this.context.drawImage(\n this.sketchCanvas,\n position.x - widthExt * scale,\n position.y - heightExt * scale,\n (this.canvas.width + 2 * widthExt) * scale,\n (this.canvas.height + 2 * heightExt) * scale,\n -widthExt,\n -heightExt,\n this.canvas.width + 2 * widthExt,\n this.canvas.height + 2 * heightExt\n );\n }\n this.context.restore();\n },\n\n // private\n drawDebugInfo: function(tile, count, i, tiledImage) {\n if ( !this.useCanvas ) {\n return;\n }\n\n var colorIndex = this.viewer.world.getIndexOfItem(tiledImage) % this.debugGridColor.length;\n var context = this.context;\n context.save();\n context.lineWidth = 2 * $.pixelDensityRatio;\n context.font = 'small-caps bold ' + (13 * $.pixelDensityRatio) + 'px arial';\n context.strokeStyle = this.debugGridColor[colorIndex];\n context.fillStyle = this.debugGridColor[colorIndex];\n\n if ( this.viewport.degrees !== 0 ) {\n this._offsetForRotation({degrees: this.viewport.degrees});\n }\n if (tiledImage.getRotation(true) % 360 !== 0) {\n this._offsetForRotation({\n degrees: tiledImage.getRotation(true),\n point: tiledImage.viewport.pixelFromPointNoRotate(\n tiledImage._getRotationPoint(true), true)\n });\n }\n\n context.strokeRect(\n tile.position.x * $.pixelDensityRatio,\n tile.position.y * $.pixelDensityRatio,\n tile.size.x * $.pixelDensityRatio,\n tile.size.y * $.pixelDensityRatio\n );\n\n var tileCenterX = (tile.position.x + (tile.size.x / 2)) * $.pixelDensityRatio;\n var tileCenterY = (tile.position.y + (tile.size.y / 2)) * $.pixelDensityRatio;\n\n // Rotate the text the right way around.\n context.translate( tileCenterX, tileCenterY );\n context.rotate( Math.PI / 180 * -this.viewport.degrees );\n context.translate( -tileCenterX, -tileCenterY );\n\n if( tile.x === 0 && tile.y === 0 ){\n context.fillText(\n \"Zoom: \" + this.viewport.getZoom(),\n tile.position.x * $.pixelDensityRatio,\n (tile.position.y - 30) * $.pixelDensityRatio\n );\n context.fillText(\n \"Pan: \" + this.viewport.getBounds().toString(),\n tile.position.x * $.pixelDensityRatio,\n (tile.position.y - 20) * $.pixelDensityRatio\n );\n }\n context.fillText(\n \"Level: \" + tile.level,\n (tile.position.x + 10) * $.pixelDensityRatio,\n (tile.position.y + 20) * $.pixelDensityRatio\n );\n context.fillText(\n \"Column: \" + tile.x,\n (tile.position.x + 10) * $.pixelDensityRatio,\n (tile.position.y + 30) * $.pixelDensityRatio\n );\n context.fillText(\n \"Row: \" + tile.y,\n (tile.position.x + 10) * $.pixelDensityRatio,\n (tile.position.y + 40) * $.pixelDensityRatio\n );\n context.fillText(\n \"Order: \" + i + \" of \" + count,\n (tile.position.x + 10) * $.pixelDensityRatio,\n (tile.position.y + 50) * $.pixelDensityRatio\n );\n context.fillText(\n \"Size: \" + tile.size.toString(),\n (tile.position.x + 10) * $.pixelDensityRatio,\n (tile.position.y + 60) * $.pixelDensityRatio\n );\n context.fillText(\n \"Position: \" + tile.position.toString(),\n (tile.position.x + 10) * $.pixelDensityRatio,\n (tile.position.y + 70) * $.pixelDensityRatio\n );\n\n if ( this.viewport.degrees !== 0 ) {\n this._restoreRotationChanges();\n }\n if (tiledImage.getRotation(true) % 360 !== 0) {\n this._restoreRotationChanges();\n }\n context.restore();\n },\n\n // private\n debugRect: function(rect) {\n if ( this.useCanvas ) {\n var context = this.context;\n context.save();\n context.lineWidth = 2 * $.pixelDensityRatio;\n context.strokeStyle = this.debugGridColor[0];\n context.fillStyle = this.debugGridColor[0];\n\n context.strokeRect(\n rect.x * $.pixelDensityRatio,\n rect.y * $.pixelDensityRatio,\n rect.width * $.pixelDensityRatio,\n rect.height * $.pixelDensityRatio\n );\n\n context.restore();\n }\n },\n\n /**\n * Get the canvas size\n * @param {Boolean} sketch If set to true return the size of the sketch canvas\n * @returns {OpenSeadragon.Point} The size of the canvas\n */\n getCanvasSize: function(sketch) {\n var canvas = this._getContext(sketch).canvas;\n return new $.Point(canvas.width, canvas.height);\n },\n\n getCanvasCenter: function() {\n return new $.Point(this.canvas.width / 2, this.canvas.height / 2);\n },\n\n // private\n _offsetForRotation: function(options) {\n var point = options.point ?\n options.point.times($.pixelDensityRatio) :\n this.getCanvasCenter();\n\n var context = this._getContext(options.useSketch);\n context.save();\n\n context.translate(point.x, point.y);\n context.rotate(Math.PI / 180 * options.degrees);\n context.translate(-point.x, -point.y);\n },\n\n // private\n _restoreRotationChanges: function(useSketch) {\n var context = this._getContext(useSketch);\n context.restore();\n },\n\n // private\n _calculateCanvasSize: function() {\n var pixelDensityRatio = $.pixelDensityRatio;\n var viewportSize = this.viewport.getContainerSize();\n return {\n x: viewportSize.x * pixelDensityRatio,\n y: viewportSize.y * pixelDensityRatio\n };\n },\n\n // private\n _calculateSketchCanvasSize: function() {\n var canvasSize = this._calculateCanvasSize();\n if (this.viewport.getRotation() === 0) {\n return canvasSize;\n }\n // If the viewport is rotated, we need a larger sketch canvas in order\n // to support edge smoothing.\n var sketchCanvasSize = Math.ceil(Math.sqrt(\n canvasSize.x * canvasSize.x +\n canvasSize.y * canvasSize.y));\n return {\n x: sketchCanvasSize,\n y: sketchCanvasSize\n };\n }\n};\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - Viewport\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n\n/**\n * @class Viewport\n * @memberof OpenSeadragon\n * @classdesc Handles coordinate-related functionality (zoom, pan, rotation, etc.)\n * for an {@link OpenSeadragon.Viewer}.\n * @param {Object} options - Options for this Viewport.\n * @param {Object} [options.margins] - See viewportMargins in {@link OpenSeadragon.Options}.\n * @param {Number} [options.springStiffness] - See springStiffness in {@link OpenSeadragon.Options}.\n * @param {Number} [options.animationTime] - See animationTime in {@link OpenSeadragon.Options}.\n * @param {Number} [options.minZoomImageRatio] - See minZoomImageRatio in {@link OpenSeadragon.Options}.\n * @param {Number} [options.maxZoomPixelRatio] - See maxZoomPixelRatio in {@link OpenSeadragon.Options}.\n * @param {Number} [options.visibilityRatio] - See visibilityRatio in {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.wrapHorizontal] - See wrapHorizontal in {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.wrapVertical] - See wrapVertical in {@link OpenSeadragon.Options}.\n * @param {Number} [options.defaultZoomLevel] - See defaultZoomLevel in {@link OpenSeadragon.Options}.\n * @param {Number} [options.minZoomLevel] - See minZoomLevel in {@link OpenSeadragon.Options}.\n * @param {Number} [options.maxZoomLevel] - See maxZoomLevel in {@link OpenSeadragon.Options}.\n * @param {Number} [options.degrees] - See degrees in {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.homeFillsViewer] - See homeFillsViewer in {@link OpenSeadragon.Options}.\n */\n$.Viewport = function( options ) {\n\n //backward compatibility for positional args while prefering more\n //idiomatic javascript options object as the only argument\n var args = arguments;\n if (args.length && args[0] instanceof $.Point) {\n options = {\n containerSize: args[0],\n contentSize: args[1],\n config: args[2]\n };\n }\n\n //options.config and the general config argument are deprecated\n //in favor of the more direct specification of optional settings\n //being passed directly on the options object\n if ( options.config ){\n $.extend( true, options, options.config );\n delete options.config;\n }\n\n this._margins = $.extend({\n left: 0,\n top: 0,\n right: 0,\n bottom: 0\n }, options.margins || {});\n\n delete options.margins;\n\n $.extend( true, this, {\n\n //required settings\n containerSize: null,\n contentSize: null,\n\n //internal state properties\n zoomPoint: null,\n viewer: null,\n\n //configurable options\n springStiffness: $.DEFAULT_SETTINGS.springStiffness,\n animationTime: $.DEFAULT_SETTINGS.animationTime,\n minZoomImageRatio: $.DEFAULT_SETTINGS.minZoomImageRatio,\n maxZoomPixelRatio: $.DEFAULT_SETTINGS.maxZoomPixelRatio,\n visibilityRatio: $.DEFAULT_SETTINGS.visibilityRatio,\n wrapHorizontal: $.DEFAULT_SETTINGS.wrapHorizontal,\n wrapVertical: $.DEFAULT_SETTINGS.wrapVertical,\n defaultZoomLevel: $.DEFAULT_SETTINGS.defaultZoomLevel,\n minZoomLevel: $.DEFAULT_SETTINGS.minZoomLevel,\n maxZoomLevel: $.DEFAULT_SETTINGS.maxZoomLevel,\n degrees: $.DEFAULT_SETTINGS.degrees,\n homeFillsViewer: $.DEFAULT_SETTINGS.homeFillsViewer\n\n }, options );\n\n this._updateContainerInnerSize();\n\n this.centerSpringX = new $.Spring({\n initial: 0,\n springStiffness: this.springStiffness,\n animationTime: this.animationTime\n });\n this.centerSpringY = new $.Spring({\n initial: 0,\n springStiffness: this.springStiffness,\n animationTime: this.animationTime\n });\n this.zoomSpring = new $.Spring({\n exponential: true,\n initial: 1,\n springStiffness: this.springStiffness,\n animationTime: this.animationTime\n });\n\n this._oldCenterX = this.centerSpringX.current.value;\n this._oldCenterY = this.centerSpringY.current.value;\n this._oldZoom = this.zoomSpring.current.value;\n\n this._setContentBounds(new $.Rect(0, 0, 1, 1), 1);\n\n this.goHome(true);\n this.update();\n};\n\n/** @lends OpenSeadragon.Viewport.prototype */\n$.Viewport.prototype = {\n /**\n * Updates the viewport's home bounds and constraints for the given content size.\n * @function\n * @param {OpenSeadragon.Point} contentSize - size of the content in content units\n * @return {OpenSeadragon.Viewport} Chainable.\n * @fires OpenSeadragon.Viewer.event:reset-size\n */\n resetContentSize: function(contentSize) {\n $.console.assert(contentSize, \"[Viewport.resetContentSize] contentSize is required\");\n $.console.assert(contentSize instanceof $.Point, \"[Viewport.resetContentSize] contentSize must be an OpenSeadragon.Point\");\n $.console.assert(contentSize.x > 0, \"[Viewport.resetContentSize] contentSize.x must be greater than 0\");\n $.console.assert(contentSize.y > 0, \"[Viewport.resetContentSize] contentSize.y must be greater than 0\");\n\n this._setContentBounds(new $.Rect(0, 0, 1, contentSize.y / contentSize.x), contentSize.x);\n return this;\n },\n\n // deprecated\n setHomeBounds: function(bounds, contentFactor) {\n $.console.error(\"[Viewport.setHomeBounds] this function is deprecated; The content bounds should not be set manually.\");\n this._setContentBounds(bounds, contentFactor);\n },\n\n // Set the viewport's content bounds\n // @param {OpenSeadragon.Rect} bounds - the new bounds in viewport coordinates\n // without rotation\n // @param {Number} contentFactor - how many content units per viewport unit\n // @fires OpenSeadragon.Viewer.event:reset-size\n // @private\n _setContentBounds: function(bounds, contentFactor) {\n $.console.assert(bounds, \"[Viewport._setContentBounds] bounds is required\");\n $.console.assert(bounds instanceof $.Rect, \"[Viewport._setContentBounds] bounds must be an OpenSeadragon.Rect\");\n $.console.assert(bounds.width > 0, \"[Viewport._setContentBounds] bounds.width must be greater than 0\");\n $.console.assert(bounds.height > 0, \"[Viewport._setContentBounds] bounds.height must be greater than 0\");\n\n this._contentBoundsNoRotate = bounds.clone();\n this._contentSizeNoRotate = this._contentBoundsNoRotate.getSize().times(\n contentFactor);\n\n this._contentBounds = bounds.rotate(this.degrees).getBoundingBox();\n this._contentSize = this._contentBounds.getSize().times(contentFactor);\n this._contentAspectRatio = this._contentSize.x / this._contentSize.y;\n\n if (this.viewer) {\n /**\n * Raised when the viewer's content size or home bounds are reset\n * (see {@link OpenSeadragon.Viewport#resetContentSize}).\n *\n * @event reset-size\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.Point} contentSize\n * @property {OpenSeadragon.Rect} contentBounds - Content bounds.\n * @property {OpenSeadragon.Rect} homeBounds - Content bounds.\n * Deprecated use contentBounds instead.\n * @property {Number} contentFactor\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.viewer.raiseEvent('reset-size', {\n contentSize: this._contentSizeNoRotate.clone(),\n contentFactor: contentFactor,\n homeBounds: this._contentBoundsNoRotate.clone(),\n contentBounds: this._contentBounds.clone()\n });\n }\n },\n\n /**\n * Returns the home zoom in \"viewport zoom\" value.\n * @function\n * @returns {Number} The home zoom in \"viewport zoom\".\n */\n getHomeZoom: function() {\n if (this.defaultZoomLevel) {\n return this.defaultZoomLevel;\n }\n\n var aspectFactor = this._contentAspectRatio / this.getAspectRatio();\n var output;\n if (this.homeFillsViewer) { // fill the viewer and clip the image\n output = aspectFactor >= 1 ? aspectFactor : 1;\n } else {\n output = aspectFactor >= 1 ? 1 : aspectFactor;\n }\n\n return output / this._contentBounds.width;\n },\n\n /**\n * Returns the home bounds in viewport coordinates.\n * @function\n * @returns {OpenSeadragon.Rect} The home bounds in vewport coordinates.\n */\n getHomeBounds: function() {\n return this.getHomeBoundsNoRotate().rotate(-this.getRotation());\n },\n\n /**\n * Returns the home bounds in viewport coordinates.\n * This method ignores the viewport rotation. Use\n * {@link OpenSeadragon.Viewport#getHomeBounds} to take it into account.\n * @function\n * @returns {OpenSeadragon.Rect} The home bounds in vewport coordinates.\n */\n getHomeBoundsNoRotate: function() {\n var center = this._contentBounds.getCenter();\n var width = 1.0 / this.getHomeZoom();\n var height = width / this.getAspectRatio();\n\n return new $.Rect(\n center.x - (width / 2.0),\n center.y - (height / 2.0),\n width,\n height\n );\n },\n\n /**\n * @function\n * @param {Boolean} immediately\n * @fires OpenSeadragon.Viewer.event:home\n */\n goHome: function(immediately) {\n if (this.viewer) {\n /**\n * Raised when the \"home\" operation occurs (see {@link OpenSeadragon.Viewport#goHome}).\n *\n * @event home\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {Boolean} immediately\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.viewer.raiseEvent('home', {\n immediately: immediately\n });\n }\n return this.fitBounds(this.getHomeBounds(), immediately);\n },\n\n /**\n * @function\n */\n getMinZoom: function() {\n var homeZoom = this.getHomeZoom(),\n zoom = this.minZoomLevel ?\n this.minZoomLevel :\n this.minZoomImageRatio * homeZoom;\n\n return zoom;\n },\n\n /**\n * @function\n */\n getMaxZoom: function() {\n var zoom = this.maxZoomLevel;\n if (!zoom) {\n zoom = this._contentSize.x * this.maxZoomPixelRatio / this._containerInnerSize.x;\n zoom /= this._contentBounds.width;\n }\n\n return Math.max( zoom, this.getHomeZoom() );\n },\n\n /**\n * @function\n */\n getAspectRatio: function() {\n return this._containerInnerSize.x / this._containerInnerSize.y;\n },\n\n /**\n * @function\n * @returns {OpenSeadragon.Point} The size of the container, in screen coordinates.\n */\n getContainerSize: function() {\n return new $.Point(\n this.containerSize.x,\n this.containerSize.y\n );\n },\n\n /**\n * The margins push the \"home\" region in from the sides by the specified amounts.\n * @function\n * @returns {Object} Properties (Numbers, in screen coordinates): left, top, right, bottom.\n */\n getMargins: function() {\n return $.extend({}, this._margins); // Make a copy so we are not returning our original\n },\n\n /**\n * The margins push the \"home\" region in from the sides by the specified amounts.\n * @function\n * @param {Object} margins - Properties (Numbers, in screen coordinates): left, top, right, bottom.\n */\n setMargins: function(margins) {\n $.console.assert($.type(margins) === 'object', '[Viewport.setMargins] margins must be an object');\n\n this._margins = $.extend({\n left: 0,\n top: 0,\n right: 0,\n bottom: 0\n }, margins);\n\n this._updateContainerInnerSize();\n if (this.viewer) {\n this.viewer.forceRedraw();\n }\n },\n\n /**\n * Returns the bounds of the visible area in viewport coordinates.\n * @function\n * @param {Boolean} current - Pass true for the current location; defaults to false (target location).\n * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, in viewport coordinates.\n */\n getBounds: function(current) {\n return this.getBoundsNoRotate(current).rotate(-this.getRotation());\n },\n\n /**\n * Returns the bounds of the visible area in viewport coordinates.\n * This method ignores the viewport rotation. Use\n * {@link OpenSeadragon.Viewport#getBounds} to take it into account.\n * @function\n * @param {Boolean} current - Pass true for the current location; defaults to false (target location).\n * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, in viewport coordinates.\n */\n getBoundsNoRotate: function(current) {\n var center = this.getCenter(current);\n var width = 1.0 / this.getZoom(current);\n var height = width / this.getAspectRatio();\n\n return new $.Rect(\n center.x - (width / 2.0),\n center.y - (height / 2.0),\n width,\n height\n );\n },\n\n /**\n * @function\n * @param {Boolean} current - Pass true for the current location; defaults to false (target location).\n * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to,\n * including the space taken by margins, in viewport coordinates.\n */\n getBoundsWithMargins: function(current) {\n return this.getBoundsNoRotateWithMargins(current).rotate(\n -this.getRotation(), this.getCenter(current));\n },\n\n /**\n * @function\n * @param {Boolean} current - Pass true for the current location; defaults to false (target location).\n * @returns {OpenSeadragon.Rect} The location you are zoomed/panned to,\n * including the space taken by margins, in viewport coordinates.\n */\n getBoundsNoRotateWithMargins: function(current) {\n var bounds = this.getBoundsNoRotate(current);\n var factor = this._containerInnerSize.x * this.getZoom(current);\n bounds.x -= this._margins.left / factor;\n bounds.y -= this._margins.top / factor;\n bounds.width += (this._margins.left + this._margins.right) / factor;\n bounds.height += (this._margins.top + this._margins.bottom) / factor;\n return bounds;\n },\n\n /**\n * @function\n * @param {Boolean} current - Pass true for the current location; defaults to false (target location).\n */\n getCenter: function( current ) {\n var centerCurrent = new $.Point(\n this.centerSpringX.current.value,\n this.centerSpringY.current.value\n ),\n centerTarget = new $.Point(\n this.centerSpringX.target.value,\n this.centerSpringY.target.value\n ),\n oldZoomPixel,\n zoom,\n width,\n height,\n bounds,\n newZoomPixel,\n deltaZoomPixels,\n deltaZoomPoints;\n\n if ( current ) {\n return centerCurrent;\n } else if ( !this.zoomPoint ) {\n return centerTarget;\n }\n\n oldZoomPixel = this.pixelFromPoint(this.zoomPoint, true);\n\n zoom = this.getZoom();\n width = 1.0 / zoom;\n height = width / this.getAspectRatio();\n bounds = new $.Rect(\n centerCurrent.x - width / 2.0,\n centerCurrent.y - height / 2.0,\n width,\n height\n );\n\n newZoomPixel = this._pixelFromPoint(this.zoomPoint, bounds);\n deltaZoomPixels = newZoomPixel.minus( oldZoomPixel );\n deltaZoomPoints = deltaZoomPixels.divide( this._containerInnerSize.x * zoom );\n\n return centerTarget.plus( deltaZoomPoints );\n },\n\n /**\n * @function\n * @param {Boolean} current - Pass true for the current location; defaults to false (target location).\n */\n getZoom: function( current ) {\n if ( current ) {\n return this.zoomSpring.current.value;\n } else {\n return this.zoomSpring.target.value;\n }\n },\n\n // private\n _applyZoomConstraints: function(zoom) {\n return Math.max(\n Math.min(zoom, this.getMaxZoom()),\n this.getMinZoom());\n },\n\n /**\n * @function\n * @private\n * @param {OpenSeadragon.Rect} bounds\n * @return {OpenSeadragon.Rect} constrained bounds.\n */\n _applyBoundaryConstraints: function(bounds) {\n var newBounds = new $.Rect(\n bounds.x,\n bounds.y,\n bounds.width,\n bounds.height);\n\n if (this.wrapHorizontal) {\n //do nothing\n } else {\n var horizontalThreshold = this.visibilityRatio * newBounds.width;\n var boundsRight = newBounds.x + newBounds.width;\n var contentRight = this._contentBoundsNoRotate.x + this._contentBoundsNoRotate.width;\n var leftDx = this._contentBoundsNoRotate.x - boundsRight + horizontalThreshold;\n var rightDx = contentRight - newBounds.x - horizontalThreshold;\n\n if (horizontalThreshold > this._contentBoundsNoRotate.width) {\n newBounds.x += (leftDx + rightDx) / 2;\n } else if (rightDx < 0) {\n newBounds.x += rightDx;\n } else if (leftDx > 0) {\n newBounds.x += leftDx;\n }\n }\n\n if (this.wrapVertical) {\n //do nothing\n } else {\n var verticalThreshold = this.visibilityRatio * newBounds.height;\n var boundsBottom = newBounds.y + newBounds.height;\n var contentBottom = this._contentBoundsNoRotate.y + this._contentBoundsNoRotate.height;\n var topDy = this._contentBoundsNoRotate.y - boundsBottom + verticalThreshold;\n var bottomDy = contentBottom - newBounds.y - verticalThreshold;\n\n if (verticalThreshold > this._contentBoundsNoRotate.height) {\n newBounds.y += (topDy + bottomDy) / 2;\n } else if (bottomDy < 0) {\n newBounds.y += bottomDy;\n } else if (topDy > 0) {\n newBounds.y += topDy;\n }\n }\n\n return newBounds;\n },\n\n /**\n * @function\n * @private\n * @param {Boolean} [immediately=false] - whether the function that triggered this event was\n * called with the \"immediately\" flag\n */\n _raiseConstraintsEvent: function(immediately) {\n if (this.viewer) {\n /**\n * Raised when the viewport constraints are applied (see {@link OpenSeadragon.Viewport#applyConstraints}).\n *\n * @event constrain\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {Boolean} immediately - whether the function that triggered this event was\n * called with the \"immediately\" flag\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.viewer.raiseEvent( 'constrain', {\n immediately: immediately\n });\n }\n },\n\n /**\n * Enforces the minZoom, maxZoom and visibilityRatio constraints by\n * zooming and panning to the closest acceptable zoom and location.\n * @function\n * @param {Boolean} [immediately=false]\n * @return {OpenSeadragon.Viewport} Chainable.\n * @fires OpenSeadragon.Viewer.event:constrain\n */\n applyConstraints: function(immediately) {\n var actualZoom = this.getZoom();\n var constrainedZoom = this._applyZoomConstraints(actualZoom);\n\n if (actualZoom !== constrainedZoom) {\n this.zoomTo(constrainedZoom, this.zoomPoint, immediately);\n }\n\n var bounds = this.getBoundsNoRotate();\n var constrainedBounds = this._applyBoundaryConstraints(bounds);\n this._raiseConstraintsEvent(immediately);\n\n if (bounds.x !== constrainedBounds.x ||\n bounds.y !== constrainedBounds.y ||\n immediately) {\n this.fitBounds(\n constrainedBounds.rotate(-this.getRotation()),\n immediately);\n }\n return this;\n },\n\n /**\n * Equivalent to {@link OpenSeadragon.Viewport#applyConstraints}\n * @function\n * @param {Boolean} [immediately=false]\n * @return {OpenSeadragon.Viewport} Chainable.\n * @fires OpenSeadragon.Viewer.event:constrain\n */\n ensureVisible: function(immediately) {\n return this.applyConstraints(immediately);\n },\n\n /**\n * @function\n * @private\n * @param {OpenSeadragon.Rect} bounds\n * @param {Object} options (immediately=false, constraints=false)\n * @return {OpenSeadragon.Viewport} Chainable.\n */\n _fitBounds: function(bounds, options) {\n options = options || {};\n var immediately = options.immediately || false;\n var constraints = options.constraints || false;\n\n var aspect = this.getAspectRatio();\n var center = bounds.getCenter();\n\n // Compute width and height of bounding box.\n var newBounds = new $.Rect(\n bounds.x,\n bounds.y,\n bounds.width,\n bounds.height,\n bounds.degrees + this.getRotation())\n .getBoundingBox();\n\n if (newBounds.getAspectRatio() >= aspect) {\n newBounds.height = newBounds.width / aspect;\n } else {\n newBounds.width = newBounds.height * aspect;\n }\n\n // Compute x and y from width, height and center position\n newBounds.x = center.x - newBounds.width / 2;\n newBounds.y = center.y - newBounds.height / 2;\n var newZoom = 1.0 / newBounds.width;\n\n if (constraints) {\n var newBoundsAspectRatio = newBounds.getAspectRatio();\n var newConstrainedZoom = this._applyZoomConstraints(newZoom);\n\n if (newZoom !== newConstrainedZoom) {\n newZoom = newConstrainedZoom;\n newBounds.width = 1.0 / newZoom;\n newBounds.x = center.x - newBounds.width / 2;\n newBounds.height = newBounds.width / newBoundsAspectRatio;\n newBounds.y = center.y - newBounds.height / 2;\n }\n\n newBounds = this._applyBoundaryConstraints(newBounds);\n center = newBounds.getCenter();\n this._raiseConstraintsEvent(immediately);\n }\n\n if (immediately) {\n this.panTo(center, true);\n return this.zoomTo(newZoom, null, true);\n }\n\n this.panTo(this.getCenter(true), true);\n this.zoomTo(this.getZoom(true), null, true);\n\n var oldBounds = this.getBounds();\n var oldZoom = this.getZoom();\n\n if (oldZoom === 0 || Math.abs(newZoom / oldZoom - 1) < 0.00000001) {\n this.zoomTo(newZoom, true);\n return this.panTo(center, immediately);\n }\n\n newBounds = newBounds.rotate(-this.getRotation());\n var referencePoint = newBounds.getTopLeft().times(newZoom)\n .minus(oldBounds.getTopLeft().times(oldZoom))\n .divide(newZoom - oldZoom);\n\n return this.zoomTo(newZoom, referencePoint, immediately);\n },\n\n /**\n * Makes the viewport zoom and pan so that the specified bounds take\n * as much space as possible in the viewport.\n * Note: this method ignores the constraints (minZoom, maxZoom and\n * visibilityRatio).\n * Use {@link OpenSeadragon.Viewport#fitBoundsWithConstraints} to enforce\n * them.\n * @function\n * @param {OpenSeadragon.Rect} bounds\n * @param {Boolean} [immediately=false]\n * @return {OpenSeadragon.Viewport} Chainable.\n */\n fitBounds: function(bounds, immediately) {\n return this._fitBounds(bounds, {\n immediately: immediately,\n constraints: false\n });\n },\n\n /**\n * Makes the viewport zoom and pan so that the specified bounds take\n * as much space as possible in the viewport while enforcing the constraints\n * (minZoom, maxZoom and visibilityRatio).\n * Note: because this method enforces the constraints, part of the\n * provided bounds may end up outside of the viewport.\n * Use {@link OpenSeadragon.Viewport#fitBounds} to ignore them.\n * @function\n * @param {OpenSeadragon.Rect} bounds\n * @param {Boolean} [immediately=false]\n * @return {OpenSeadragon.Viewport} Chainable.\n */\n fitBoundsWithConstraints: function(bounds, immediately) {\n return this._fitBounds(bounds, {\n immediately: immediately,\n constraints: true\n });\n },\n\n /**\n * Zooms so the image just fills the viewer vertically.\n * @param {Boolean} immediately\n * @return {OpenSeadragon.Viewport} Chainable.\n */\n fitVertically: function(immediately) {\n var box = new $.Rect(\n this._contentBounds.x + (this._contentBounds.width / 2),\n this._contentBounds.y,\n 0,\n this._contentBounds.height);\n return this.fitBounds(box, immediately);\n },\n\n /**\n * Zooms so the image just fills the viewer horizontally.\n * @param {Boolean} immediately\n * @return {OpenSeadragon.Viewport} Chainable.\n */\n fitHorizontally: function(immediately) {\n var box = new $.Rect(\n this._contentBounds.x,\n this._contentBounds.y + (this._contentBounds.height / 2),\n this._contentBounds.width,\n 0);\n return this.fitBounds(box, immediately);\n },\n\n\n /**\n * Returns bounds taking constraints into account\n * Added to improve constrained panning\n * @param {Boolean} current - Pass true for the current location; defaults to false (target location).\n * @return {OpenSeadragon.Viewport} Chainable.\n */\n getConstrainedBounds: function(current) {\n var bounds,\n constrainedBounds;\n\n bounds = this.getBounds(current);\n\n constrainedBounds = this._applyBoundaryConstraints(bounds);\n\n return constrainedBounds;\n },\n\n /**\n * @function\n * @param {OpenSeadragon.Point} delta\n * @param {Boolean} immediately\n * @return {OpenSeadragon.Viewport} Chainable.\n * @fires OpenSeadragon.Viewer.event:pan\n */\n panBy: function( delta, immediately ) {\n var center = new $.Point(\n this.centerSpringX.target.value,\n this.centerSpringY.target.value\n );\n return this.panTo( center.plus( delta ), immediately );\n },\n\n /**\n * @function\n * @param {OpenSeadragon.Point} center\n * @param {Boolean} immediately\n * @return {OpenSeadragon.Viewport} Chainable.\n * @fires OpenSeadragon.Viewer.event:pan\n */\n panTo: function( center, immediately ) {\n if ( immediately ) {\n this.centerSpringX.resetTo( center.x );\n this.centerSpringY.resetTo( center.y );\n } else {\n this.centerSpringX.springTo( center.x );\n this.centerSpringY.springTo( center.y );\n }\n\n if( this.viewer ){\n /**\n * Raised when the viewport is panned (see {@link OpenSeadragon.Viewport#panBy} and {@link OpenSeadragon.Viewport#panTo}).\n *\n * @event pan\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.Point} center\n * @property {Boolean} immediately\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.viewer.raiseEvent( 'pan', {\n center: center,\n immediately: immediately\n });\n }\n\n return this;\n },\n\n /**\n * @function\n * @return {OpenSeadragon.Viewport} Chainable.\n * @fires OpenSeadragon.Viewer.event:zoom\n */\n zoomBy: function(factor, refPoint, immediately) {\n return this.zoomTo(\n this.zoomSpring.target.value * factor, refPoint, immediately);\n },\n\n /**\n * Zooms to the specified zoom level\n * @function\n * @param {Number} zoom The zoom level to zoom to.\n * @param {OpenSeadragon.Point} [refPoint] The point which will stay at\n * the same screen location. Defaults to the viewport center.\n * @param {Boolean} [immediately=false]\n * @return {OpenSeadragon.Viewport} Chainable.\n * @fires OpenSeadragon.Viewer.event:zoom\n */\n zoomTo: function(zoom, refPoint, immediately) {\n var _this = this;\n\n this.zoomPoint = refPoint instanceof $.Point &&\n !isNaN(refPoint.x) &&\n !isNaN(refPoint.y) ?\n refPoint :\n null;\n\n if (immediately) {\n this._adjustCenterSpringsForZoomPoint(function() {\n _this.zoomSpring.resetTo(zoom);\n });\n } else {\n this.zoomSpring.springTo(zoom);\n }\n\n if (this.viewer) {\n /**\n * Raised when the viewport zoom level changes (see {@link OpenSeadragon.Viewport#zoomBy} and {@link OpenSeadragon.Viewport#zoomTo}).\n *\n * @event zoom\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {Number} zoom\n * @property {OpenSeadragon.Point} refPoint\n * @property {Boolean} immediately\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.viewer.raiseEvent('zoom', {\n zoom: zoom,\n refPoint: refPoint,\n immediately: immediately\n });\n }\n\n return this;\n },\n\n /**\n * Rotates this viewport to the angle specified.\n * @function\n * @return {OpenSeadragon.Viewport} Chainable.\n */\n setRotation: function(degrees) {\n if (!this.viewer || !this.viewer.drawer.canRotate()) {\n return this;\n }\n\n this.degrees = $.positiveModulo(degrees, 360);\n this._setContentBounds(\n this.viewer.world.getHomeBounds(),\n this.viewer.world.getContentFactor());\n this.viewer.forceRedraw();\n\n /**\n * Raised when rotation has been changed.\n *\n * @event rotate\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {Number} degrees - The number of degrees the rotation was set to.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.viewer.raiseEvent('rotate', {\"degrees\": degrees});\n return this;\n },\n\n /**\n * Gets the current rotation in degrees.\n * @function\n * @return {Number} The current rotation in degrees.\n */\n getRotation: function() {\n return this.degrees;\n },\n\n /**\n * @function\n * @return {OpenSeadragon.Viewport} Chainable.\n * @fires OpenSeadragon.Viewer.event:resize\n */\n resize: function( newContainerSize, maintain ) {\n var oldBounds = this.getBoundsNoRotate(),\n newBounds = oldBounds,\n widthDeltaFactor;\n\n this.containerSize.x = newContainerSize.x;\n this.containerSize.y = newContainerSize.y;\n\n this._updateContainerInnerSize();\n\n if ( maintain ) {\n // TODO: widthDeltaFactor will always be 1; probably not what's intended\n widthDeltaFactor = newContainerSize.x / this.containerSize.x;\n newBounds.width = oldBounds.width * widthDeltaFactor;\n newBounds.height = newBounds.width / this.getAspectRatio();\n }\n\n if( this.viewer ){\n /**\n * Raised when the viewer is resized (see {@link OpenSeadragon.Viewport#resize}).\n *\n * @event resize\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.\n * @property {OpenSeadragon.Point} newContainerSize\n * @property {Boolean} maintain\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.viewer.raiseEvent( 'resize', {\n newContainerSize: newContainerSize,\n maintain: maintain\n });\n }\n\n return this.fitBounds( newBounds, true );\n },\n\n // private\n _updateContainerInnerSize: function() {\n this._containerInnerSize = new $.Point(\n Math.max(1, this.containerSize.x - (this._margins.left + this._margins.right)),\n Math.max(1, this.containerSize.y - (this._margins.top + this._margins.bottom))\n );\n },\n\n /**\n * Update the zoom and center (X and Y) springs.\n * @function\n * @returns {Boolean} True if any change has been made, false otherwise.\n */\n update: function() {\n var _this = this;\n this._adjustCenterSpringsForZoomPoint(function() {\n _this.zoomSpring.update();\n });\n\n this.centerSpringX.update();\n this.centerSpringY.update();\n\n var changed = this.centerSpringX.current.value !== this._oldCenterX ||\n this.centerSpringY.current.value !== this._oldCenterY ||\n this.zoomSpring.current.value !== this._oldZoom;\n\n this._oldCenterX = this.centerSpringX.current.value;\n this._oldCenterY = this.centerSpringY.current.value;\n this._oldZoom = this.zoomSpring.current.value;\n\n return changed;\n },\n\n _adjustCenterSpringsForZoomPoint: function(zoomSpringHandler) {\n if (this.zoomPoint) {\n var oldZoomPixel = this.pixelFromPoint(this.zoomPoint, true);\n zoomSpringHandler();\n var newZoomPixel = this.pixelFromPoint(this.zoomPoint, true);\n\n var deltaZoomPixels = newZoomPixel.minus(oldZoomPixel);\n var deltaZoomPoints = this.deltaPointsFromPixels(\n deltaZoomPixels, true);\n\n this.centerSpringX.shiftBy(deltaZoomPoints.x);\n this.centerSpringY.shiftBy(deltaZoomPoints.y);\n\n if (this.zoomSpring.isAtTargetValue()) {\n this.zoomPoint = null;\n }\n } else {\n zoomSpringHandler();\n }\n },\n\n /**\n * Convert a delta (translation vector) from viewport coordinates to pixels\n * coordinates. This method does not take rotation into account.\n * Consider using deltaPixelsFromPoints if you need to account for rotation.\n * @param {OpenSeadragon.Point} deltaPoints - The translation vector to convert.\n * @param {Boolean} [current=false] - Pass true for the current location;\n * defaults to false (target location).\n * @returns {OpenSeadragon.Point}\n */\n deltaPixelsFromPointsNoRotate: function(deltaPoints, current) {\n return deltaPoints.times(\n this._containerInnerSize.x * this.getZoom(current)\n );\n },\n\n /**\n * Convert a delta (translation vector) from viewport coordinates to pixels\n * coordinates.\n * @param {OpenSeadragon.Point} deltaPoints - The translation vector to convert.\n * @param {Boolean} [current=false] - Pass true for the current location;\n * defaults to false (target location).\n * @returns {OpenSeadragon.Point}\n */\n deltaPixelsFromPoints: function(deltaPoints, current) {\n return this.deltaPixelsFromPointsNoRotate(\n deltaPoints.rotate(this.getRotation()),\n current);\n },\n\n /**\n * Convert a delta (translation vector) from pixels coordinates to viewport\n * coordinates. This method does not take rotation into account.\n * Consider using deltaPointsFromPixels if you need to account for rotation.\n * @param {OpenSeadragon.Point} deltaPixels - The translation vector to convert.\n * @param {Boolean} [current=false] - Pass true for the current location;\n * defaults to false (target location).\n * @returns {OpenSeadragon.Point}\n */\n deltaPointsFromPixelsNoRotate: function(deltaPixels, current) {\n return deltaPixels.divide(\n this._containerInnerSize.x * this.getZoom(current)\n );\n },\n\n /**\n * Convert a delta (translation vector) from pixels coordinates to viewport\n * coordinates.\n * @param {OpenSeadragon.Point} deltaPixels - The translation vector to convert.\n * @param {Boolean} [current=false] - Pass true for the current location;\n * defaults to false (target location).\n * @returns {OpenSeadragon.Point}\n */\n deltaPointsFromPixels: function(deltaPixels, current) {\n return this.deltaPointsFromPixelsNoRotate(deltaPixels, current)\n .rotate(-this.getRotation());\n },\n\n /**\n * Convert viewport coordinates to pixels coordinates.\n * This method does not take rotation into account.\n * Consider using pixelFromPoint if you need to account for rotation.\n * @param {OpenSeadragon.Point} point the viewport coordinates\n * @param {Boolean} [current=false] - Pass true for the current location;\n * defaults to false (target location).\n * @returns {OpenSeadragon.Point}\n */\n pixelFromPointNoRotate: function(point, current) {\n return this._pixelFromPointNoRotate(\n point, this.getBoundsNoRotate(current));\n },\n\n /**\n * Convert viewport coordinates to pixel coordinates.\n * @param {OpenSeadragon.Point} point the viewport coordinates\n * @param {Boolean} [current=false] - Pass true for the current location;\n * defaults to false (target location).\n * @returns {OpenSeadragon.Point}\n */\n pixelFromPoint: function(point, current) {\n return this._pixelFromPoint(point, this.getBoundsNoRotate(current));\n },\n\n // private\n _pixelFromPointNoRotate: function(point, bounds) {\n return point.minus(\n bounds.getTopLeft()\n ).times(\n this._containerInnerSize.x / bounds.width\n ).plus(\n new $.Point(this._margins.left, this._margins.top)\n );\n },\n\n // private\n _pixelFromPoint: function(point, bounds) {\n return this._pixelFromPointNoRotate(\n point.rotate(this.getRotation(), this.getCenter(true)),\n bounds);\n },\n\n /**\n * Convert pixel coordinates to viewport coordinates.\n * This method does not take rotation into account.\n * Consider using pointFromPixel if you need to account for rotation.\n * @param {OpenSeadragon.Point} pixel Pixel coordinates\n * @param {Boolean} [current=false] - Pass true for the current location;\n * defaults to false (target location).\n * @returns {OpenSeadragon.Point}\n */\n pointFromPixelNoRotate: function(pixel, current) {\n var bounds = this.getBoundsNoRotate(current);\n return pixel.minus(\n new $.Point(this._margins.left, this._margins.top)\n ).divide(\n this._containerInnerSize.x / bounds.width\n ).plus(\n bounds.getTopLeft()\n );\n },\n\n /**\n * Convert pixel coordinates to viewport coordinates.\n * @param {OpenSeadragon.Point} pixel Pixel coordinates\n * @param {Boolean} [current=false] - Pass true for the current location;\n * defaults to false (target location).\n * @returns {OpenSeadragon.Point}\n */\n pointFromPixel: function(pixel, current) {\n return this.pointFromPixelNoRotate(pixel, current).rotate(\n -this.getRotation(),\n this.getCenter(true)\n );\n },\n\n // private\n _viewportToImageDelta: function( viewerX, viewerY ) {\n var scale = this._contentBoundsNoRotate.width;\n return new $.Point(\n viewerX * this._contentSizeNoRotate.x / scale,\n viewerY * this._contentSizeNoRotate.x / scale);\n },\n\n /**\n * Translates from OpenSeadragon viewer coordinate system to image coordinate system.\n * This method can be called either by passing X,Y coordinates or an\n * OpenSeadragon.Point\n * Note: not accurate with multi-image; use TiledImage.viewportToImageCoordinates instead.\n * @function\n * @param {(OpenSeadragon.Point|Number)} viewerX either a point or the X\n * coordinate in viewport coordinate system.\n * @param {Number} [viewerY] Y coordinate in viewport coordinate system.\n * @return {OpenSeadragon.Point} a point representing the coordinates in the image.\n */\n viewportToImageCoordinates: function(viewerX, viewerY) {\n if (viewerX instanceof $.Point) {\n //they passed a point instead of individual components\n return this.viewportToImageCoordinates(viewerX.x, viewerX.y);\n }\n\n if (this.viewer) {\n var count = this.viewer.world.getItemCount();\n if (count > 1) {\n $.console.error('[Viewport.viewportToImageCoordinates] is not accurate ' +\n 'with multi-image; use TiledImage.viewportToImageCoordinates instead.');\n } else if (count === 1) {\n // It is better to use TiledImage.viewportToImageCoordinates\n // because this._contentBoundsNoRotate can not be relied on\n // with clipping.\n var item = this.viewer.world.getItemAt(0);\n return item.viewportToImageCoordinates(viewerX, viewerY, true);\n }\n }\n\n return this._viewportToImageDelta(\n viewerX - this._contentBoundsNoRotate.x,\n viewerY - this._contentBoundsNoRotate.y);\n },\n\n // private\n _imageToViewportDelta: function( imageX, imageY ) {\n var scale = this._contentBoundsNoRotate.width;\n return new $.Point(\n imageX / this._contentSizeNoRotate.x * scale,\n imageY / this._contentSizeNoRotate.x * scale);\n },\n\n /**\n * Translates from image coordinate system to OpenSeadragon viewer coordinate system\n * This method can be called either by passing X,Y coordinates or an\n * OpenSeadragon.Point\n * Note: not accurate with multi-image; use TiledImage.imageToViewportCoordinates instead.\n * @function\n * @param {(OpenSeadragon.Point | Number)} imageX the point or the\n * X coordinate in image coordinate system.\n * @param {Number} [imageY] Y coordinate in image coordinate system.\n * @return {OpenSeadragon.Point} a point representing the coordinates in the viewport.\n */\n imageToViewportCoordinates: function(imageX, imageY) {\n if (imageX instanceof $.Point) {\n //they passed a point instead of individual components\n return this.imageToViewportCoordinates(imageX.x, imageX.y);\n }\n\n if (this.viewer) {\n var count = this.viewer.world.getItemCount();\n if (count > 1) {\n $.console.error('[Viewport.imageToViewportCoordinates] is not accurate ' +\n 'with multi-image; use TiledImage.imageToViewportCoordinates instead.');\n } else if (count === 1) {\n // It is better to use TiledImage.viewportToImageCoordinates\n // because this._contentBoundsNoRotate can not be relied on\n // with clipping.\n var item = this.viewer.world.getItemAt(0);\n return item.imageToViewportCoordinates(imageX, imageY, true);\n }\n }\n\n var point = this._imageToViewportDelta(imageX, imageY);\n point.x += this._contentBoundsNoRotate.x;\n point.y += this._contentBoundsNoRotate.y;\n return point;\n },\n\n /**\n * Translates from a rectangle which describes a portion of the image in\n * pixel coordinates to OpenSeadragon viewport rectangle coordinates.\n * This method can be called either by passing X,Y,width,height or an\n * OpenSeadragon.Rect\n * Note: not accurate with multi-image; use TiledImage.imageToViewportRectangle instead.\n * @function\n * @param {(OpenSeadragon.Rect | Number)} imageX the rectangle or the X\n * coordinate of the top left corner of the rectangle in image coordinate system.\n * @param {Number} [imageY] the Y coordinate of the top left corner of the rectangle\n * in image coordinate system.\n * @param {Number} [pixelWidth] the width in pixel of the rectangle.\n * @param {Number} [pixelHeight] the height in pixel of the rectangle.\n * @returns {OpenSeadragon.Rect} This image's bounds in viewport coordinates\n */\n imageToViewportRectangle: function(imageX, imageY, pixelWidth, pixelHeight) {\n var rect = imageX;\n if (!(rect instanceof $.Rect)) {\n //they passed individual components instead of a rectangle\n rect = new $.Rect(imageX, imageY, pixelWidth, pixelHeight);\n }\n\n if (this.viewer) {\n var count = this.viewer.world.getItemCount();\n if (count > 1) {\n $.console.error('[Viewport.imageToViewportRectangle] is not accurate ' +\n 'with multi-image; use TiledImage.imageToViewportRectangle instead.');\n } else if (count === 1) {\n // It is better to use TiledImage.imageToViewportRectangle\n // because this._contentBoundsNoRotate can not be relied on\n // with clipping.\n var item = this.viewer.world.getItemAt(0);\n return item.imageToViewportRectangle(\n imageX, imageY, pixelWidth, pixelHeight, true);\n }\n }\n\n var coordA = this.imageToViewportCoordinates(rect.x, rect.y);\n var coordB = this._imageToViewportDelta(rect.width, rect.height);\n return new $.Rect(\n coordA.x,\n coordA.y,\n coordB.x,\n coordB.y,\n rect.degrees\n );\n },\n\n /**\n * Translates from a rectangle which describes a portion of\n * the viewport in point coordinates to image rectangle coordinates.\n * This method can be called either by passing X,Y,width,height or an\n * OpenSeadragon.Rect\n * Note: not accurate with multi-image; use TiledImage.viewportToImageRectangle instead.\n * @function\n * @param {(OpenSeadragon.Rect | Number)} viewerX either a rectangle or\n * the X coordinate of the top left corner of the rectangle in viewport\n * coordinate system.\n * @param {Number} [viewerY] the Y coordinate of the top left corner of the rectangle\n * in viewport coordinate system.\n * @param {Number} [pointWidth] the width of the rectangle in viewport coordinate system.\n * @param {Number} [pointHeight] the height of the rectangle in viewport coordinate system.\n */\n viewportToImageRectangle: function(viewerX, viewerY, pointWidth, pointHeight) {\n var rect = viewerX;\n if (!(rect instanceof $.Rect)) {\n //they passed individual components instead of a rectangle\n rect = new $.Rect(viewerX, viewerY, pointWidth, pointHeight);\n }\n\n if (this.viewer) {\n var count = this.viewer.world.getItemCount();\n if (count > 1) {\n $.console.error('[Viewport.viewportToImageRectangle] is not accurate ' +\n 'with multi-image; use TiledImage.viewportToImageRectangle instead.');\n } else if (count === 1) {\n // It is better to use TiledImage.viewportToImageCoordinates\n // because this._contentBoundsNoRotate can not be relied on\n // with clipping.\n var item = this.viewer.world.getItemAt(0);\n return item.viewportToImageRectangle(\n viewerX, viewerY, pointWidth, pointHeight, true);\n }\n }\n\n var coordA = this.viewportToImageCoordinates(rect.x, rect.y);\n var coordB = this._viewportToImageDelta(rect.width, rect.height);\n return new $.Rect(\n coordA.x,\n coordA.y,\n coordB.x,\n coordB.y,\n rect.degrees\n );\n },\n\n /**\n * Convert pixel coordinates relative to the viewer element to image\n * coordinates.\n * Note: not accurate with multi-image.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n viewerElementToImageCoordinates: function( pixel ) {\n var point = this.pointFromPixel( pixel, true );\n return this.viewportToImageCoordinates( point );\n },\n\n /**\n * Convert pixel coordinates relative to the image to\n * viewer element coordinates.\n * Note: not accurate with multi-image.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n imageToViewerElementCoordinates: function( pixel ) {\n var point = this.imageToViewportCoordinates( pixel );\n return this.pixelFromPoint( point, true );\n },\n\n /**\n * Convert pixel coordinates relative to the window to image coordinates.\n * Note: not accurate with multi-image.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n windowToImageCoordinates: function(pixel) {\n $.console.assert(this.viewer,\n \"[Viewport.windowToImageCoordinates] the viewport must have a viewer.\");\n var viewerCoordinates = pixel.minus(\n $.getElementPosition(this.viewer.element));\n return this.viewerElementToImageCoordinates(viewerCoordinates);\n },\n\n /**\n * Convert image coordinates to pixel coordinates relative to the window.\n * Note: not accurate with multi-image.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n imageToWindowCoordinates: function(pixel) {\n $.console.assert(this.viewer,\n \"[Viewport.imageToWindowCoordinates] the viewport must have a viewer.\");\n var viewerCoordinates = this.imageToViewerElementCoordinates(pixel);\n return viewerCoordinates.plus(\n $.getElementPosition(this.viewer.element));\n },\n\n /**\n * Convert pixel coordinates relative to the viewer element to viewport\n * coordinates.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n viewerElementToViewportCoordinates: function( pixel ) {\n return this.pointFromPixel( pixel, true );\n },\n\n /**\n * Convert viewport coordinates to pixel coordinates relative to the\n * viewer element.\n * @param {OpenSeadragon.Point} point\n * @returns {OpenSeadragon.Point}\n */\n viewportToViewerElementCoordinates: function( point ) {\n return this.pixelFromPoint( point, true );\n },\n\n /**\n * Convert a rectangle in pixel coordinates relative to the viewer element\n * to viewport coordinates.\n * @param {OpenSeadragon.Rect} rectangle the rectangle to convert\n * @returns {OpenSeadragon.Rect} the converted rectangle\n */\n viewerElementToViewportRectangle: function(rectangle) {\n return $.Rect.fromSummits(\n this.pointFromPixel(rectangle.getTopLeft(), true),\n this.pointFromPixel(rectangle.getTopRight(), true),\n this.pointFromPixel(rectangle.getBottomLeft(), true)\n );\n },\n\n /**\n * Convert a rectangle in viewport coordinates to pixel coordinates relative\n * to the viewer element.\n * @param {OpenSeadragon.Rect} rectangle the rectangle to convert\n * @returns {OpenSeadragon.Rect} the converted rectangle\n */\n viewportToViewerElementRectangle: function(rectangle) {\n return $.Rect.fromSummits(\n this.pixelFromPoint(rectangle.getTopLeft(), true),\n this.pixelFromPoint(rectangle.getTopRight(), true),\n this.pixelFromPoint(rectangle.getBottomLeft(), true)\n );\n },\n\n /**\n * Convert pixel coordinates relative to the window to viewport coordinates.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n windowToViewportCoordinates: function(pixel) {\n $.console.assert(this.viewer,\n \"[Viewport.windowToViewportCoordinates] the viewport must have a viewer.\");\n var viewerCoordinates = pixel.minus(\n $.getElementPosition(this.viewer.element));\n return this.viewerElementToViewportCoordinates(viewerCoordinates);\n },\n\n /**\n * Convert viewport coordinates to pixel coordinates relative to the window.\n * @param {OpenSeadragon.Point} point\n * @returns {OpenSeadragon.Point}\n */\n viewportToWindowCoordinates: function(point) {\n $.console.assert(this.viewer,\n \"[Viewport.viewportToWindowCoordinates] the viewport must have a viewer.\");\n var viewerCoordinates = this.viewportToViewerElementCoordinates(point);\n return viewerCoordinates.plus(\n $.getElementPosition(this.viewer.element));\n },\n\n /**\n * Convert a viewport zoom to an image zoom.\n * Image zoom: ratio of the original image size to displayed image size.\n * 1 means original image size, 0.5 half size...\n * Viewport zoom: ratio of the displayed image's width to viewport's width.\n * 1 means identical width, 2 means image's width is twice the viewport's width...\n * Note: not accurate with multi-image.\n * @function\n * @param {Number} viewportZoom The viewport zoom\n * target zoom.\n * @returns {Number} imageZoom The image zoom\n */\n viewportToImageZoom: function(viewportZoom) {\n if (this.viewer) {\n var count = this.viewer.world.getItemCount();\n if (count > 1) {\n $.console.error('[Viewport.viewportToImageZoom] is not ' +\n 'accurate with multi-image.');\n } else if (count === 1) {\n // It is better to use TiledImage.viewportToImageZoom\n // because this._contentBoundsNoRotate can not be relied on\n // with clipping.\n var item = this.viewer.world.getItemAt(0);\n return item.viewportToImageZoom(viewportZoom);\n }\n }\n\n var imageWidth = this._contentSizeNoRotate.x;\n var containerWidth = this._containerInnerSize.x;\n var scale = this._contentBoundsNoRotate.width;\n var viewportToImageZoomRatio = (containerWidth / imageWidth) * scale;\n return viewportZoom * viewportToImageZoomRatio;\n },\n\n /**\n * Convert an image zoom to a viewport zoom.\n * Image zoom: ratio of the original image size to displayed image size.\n * 1 means original image size, 0.5 half size...\n * Viewport zoom: ratio of the displayed image's width to viewport's width.\n * 1 means identical width, 2 means image's width is twice the viewport's width...\n * Note: not accurate with multi-image.\n * @function\n * @param {Number} imageZoom The image zoom\n * target zoom.\n * @returns {Number} viewportZoom The viewport zoom\n */\n imageToViewportZoom: function(imageZoom) {\n if (this.viewer) {\n var count = this.viewer.world.getItemCount();\n if (count > 1) {\n $.console.error('[Viewport.imageToViewportZoom] is not accurate ' +\n 'with multi-image.');\n } else if (count === 1) {\n // It is better to use TiledImage.imageToViewportZoom\n // because this._contentBoundsNoRotate can not be relied on\n // with clipping.\n var item = this.viewer.world.getItemAt(0);\n return item.imageToViewportZoom(imageZoom);\n }\n }\n\n var imageWidth = this._contentSizeNoRotate.x;\n var containerWidth = this._containerInnerSize.x;\n var scale = this._contentBoundsNoRotate.width;\n var viewportToImageZoomRatio = (imageWidth / containerWidth) / scale;\n return imageZoom * viewportToImageZoomRatio;\n }\n};\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - TiledImage\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * You shouldn't have to create a TiledImage directly; use {@link OpenSeadragon.Viewer#open}\n * or {@link OpenSeadragon.Viewer#addTiledImage} instead.\n * @class TiledImage\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.EventSource\n * @classdesc Handles rendering of tiles for an {@link OpenSeadragon.Viewer}.\n * A new instance is created for each TileSource opened.\n * @param {Object} options - Configuration for this TiledImage.\n * @param {OpenSeadragon.TileSource} options.source - The TileSource that defines this TiledImage.\n * @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this TiledImage.\n * @param {OpenSeadragon.TileCache} options.tileCache - The TileCache for this TiledImage to use.\n * @param {OpenSeadragon.Drawer} options.drawer - The Drawer for this TiledImage to draw onto.\n * @param {OpenSeadragon.ImageLoader} options.imageLoader - The ImageLoader for this TiledImage to use.\n * @param {Number} [options.x=0] - Left position, in viewport coordinates.\n * @param {Number} [options.y=0] - Top position, in viewport coordinates.\n * @param {Number} [options.width=1] - Width, in viewport coordinates.\n * @param {Number} [options.height] - Height, in viewport coordinates.\n * @param {OpenSeadragon.Rect} [options.fitBounds] The bounds in viewport coordinates\n * to fit the image into. If specified, x, y, width and height get ignored.\n * @param {OpenSeadragon.Placement} [options.fitBoundsPlacement=OpenSeadragon.Placement.CENTER]\n * How to anchor the image in the bounds if options.fitBounds is set.\n * @param {OpenSeadragon.Rect} [options.clip] - An area, in image pixels, to clip to\n * (portions of the image outside of this area will not be visible). Only works on\n * browsers that support the HTML5 canvas.\n * @param {Number} [options.springStiffness] - See {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.animationTime] - See {@link OpenSeadragon.Options}.\n * @param {Number} [options.minZoomImageRatio] - See {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.wrapHorizontal] - See {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.wrapVertical] - See {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.immediateRender] - See {@link OpenSeadragon.Options}.\n * @param {Number} [options.blendTime] - See {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.alwaysBlend] - See {@link OpenSeadragon.Options}.\n * @param {Number} [options.minPixelRatio] - See {@link OpenSeadragon.Options}.\n * @param {Number} [options.smoothTileEdgesMinZoom] - See {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.iOSDevice] - See {@link OpenSeadragon.Options}.\n * @param {Number} [options.opacity=1] - Set to draw at proportional opacity. If zero, images will not draw.\n * @param {Boolean} [options.preload=false] - Set true to load even when the image is hidden by zero opacity.\n * @param {String} [options.compositeOperation] - How the image is composited onto other images; see compositeOperation in {@link OpenSeadragon.Options} for possible values.\n * @param {Boolean} [options.debugMode] - See {@link OpenSeadragon.Options}.\n * @param {String|CanvasGradient|CanvasPattern|Function} [options.placeholderFillStyle] - See {@link OpenSeadragon.Options}.\n * @param {String|Boolean} [options.crossOriginPolicy] - See {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.ajaxWithCredentials] - See {@link OpenSeadragon.Options}.\n * @param {Boolean} [options.loadTilesWithAjax]\n * Whether to load tile data using AJAX requests.\n * Defaults to the setting in {@link OpenSeadragon.Options}.\n * @param {Object} [options.ajaxHeaders={}]\n * A set of headers to include when making tile AJAX requests.\n */\n$.TiledImage = function( options ) {\n var _this = this;\n\n $.console.assert( options.tileCache, \"[TiledImage] options.tileCache is required\" );\n $.console.assert( options.drawer, \"[TiledImage] options.drawer is required\" );\n $.console.assert( options.viewer, \"[TiledImage] options.viewer is required\" );\n $.console.assert( options.imageLoader, \"[TiledImage] options.imageLoader is required\" );\n $.console.assert( options.source, \"[TiledImage] options.source is required\" );\n $.console.assert(!options.clip || options.clip instanceof $.Rect,\n \"[TiledImage] options.clip must be an OpenSeadragon.Rect if present\");\n\n $.EventSource.call( this );\n\n this._tileCache = options.tileCache;\n delete options.tileCache;\n\n this._drawer = options.drawer;\n delete options.drawer;\n\n this._imageLoader = options.imageLoader;\n delete options.imageLoader;\n\n if (options.clip instanceof $.Rect) {\n this._clip = options.clip.clone();\n }\n\n delete options.clip;\n\n var x = options.x || 0;\n delete options.x;\n var y = options.y || 0;\n delete options.y;\n\n // Ratio of zoomable image height to width.\n this.normHeight = options.source.dimensions.y / options.source.dimensions.x;\n this.contentAspectX = options.source.dimensions.x / options.source.dimensions.y;\n\n var scale = 1;\n if ( options.width ) {\n scale = options.width;\n delete options.width;\n\n if ( options.height ) {\n $.console.error( \"specifying both width and height to a tiledImage is not supported\" );\n delete options.height;\n }\n } else if ( options.height ) {\n scale = options.height / this.normHeight;\n delete options.height;\n }\n\n var fitBounds = options.fitBounds;\n delete options.fitBounds;\n var fitBoundsPlacement = options.fitBoundsPlacement || OpenSeadragon.Placement.CENTER;\n delete options.fitBoundsPlacement;\n\n var degrees = options.degrees || 0;\n delete options.degrees;\n\n $.extend( true, this, {\n\n //internal state properties\n viewer: null,\n tilesMatrix: {}, // A '3d' dictionary [level][x][y] --> Tile.\n coverage: {}, // A '3d' dictionary [level][x][y] --> Boolean; shows what areas have been drawn.\n loadingCoverage: {}, // A '3d' dictionary [level][x][y] --> Boolean; shows what areas are loaded or are being loaded/blended.\n lastDrawn: [], // An unordered list of Tiles drawn last frame.\n lastResetTime: 0, // Last time for which the tiledImage was reset.\n _midDraw: false, // Is the tiledImage currently updating the viewport?\n _needsDraw: true, // Does the tiledImage need to update the viewport again?\n _hasOpaqueTile: false, // Do we have even one fully opaque tile?\n _tilesLoading: 0, // The number of pending tile requests.\n //configurable settings\n springStiffness: $.DEFAULT_SETTINGS.springStiffness,\n animationTime: $.DEFAULT_SETTINGS.animationTime,\n minZoomImageRatio: $.DEFAULT_SETTINGS.minZoomImageRatio,\n wrapHorizontal: $.DEFAULT_SETTINGS.wrapHorizontal,\n wrapVertical: $.DEFAULT_SETTINGS.wrapVertical,\n immediateRender: $.DEFAULT_SETTINGS.immediateRender,\n blendTime: $.DEFAULT_SETTINGS.blendTime,\n alwaysBlend: $.DEFAULT_SETTINGS.alwaysBlend,\n minPixelRatio: $.DEFAULT_SETTINGS.minPixelRatio,\n smoothTileEdgesMinZoom: $.DEFAULT_SETTINGS.smoothTileEdgesMinZoom,\n iOSDevice: $.DEFAULT_SETTINGS.iOSDevice,\n debugMode: $.DEFAULT_SETTINGS.debugMode,\n crossOriginPolicy: $.DEFAULT_SETTINGS.crossOriginPolicy,\n ajaxWithCredentials: $.DEFAULT_SETTINGS.ajaxWithCredentials,\n placeholderFillStyle: $.DEFAULT_SETTINGS.placeholderFillStyle,\n opacity: $.DEFAULT_SETTINGS.opacity,\n preload: $.DEFAULT_SETTINGS.preload,\n compositeOperation: $.DEFAULT_SETTINGS.compositeOperation\n }, options );\n\n this._preload = this.preload;\n delete this.preload;\n\n this._fullyLoaded = false;\n\n this._xSpring = new $.Spring({\n initial: x,\n springStiffness: this.springStiffness,\n animationTime: this.animationTime\n });\n\n this._ySpring = new $.Spring({\n initial: y,\n springStiffness: this.springStiffness,\n animationTime: this.animationTime\n });\n\n this._scaleSpring = new $.Spring({\n initial: scale,\n springStiffness: this.springStiffness,\n animationTime: this.animationTime\n });\n\n this._degreesSpring = new $.Spring({\n initial: degrees,\n springStiffness: this.springStiffness,\n animationTime: this.animationTime\n });\n\n this._updateForScale();\n\n if (fitBounds) {\n this.fitBounds(fitBounds, fitBoundsPlacement, true);\n }\n\n // We need a callback to give image manipulation a chance to happen\n this._drawingHandler = function(args) {\n /**\n * This event is fired just before the tile is drawn giving the application a chance to alter the image.\n *\n * NOTE: This event is only fired when the drawer is using a <canvas>.\n *\n * @event tile-drawing\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {OpenSeadragon.Tile} tile - The Tile being drawn.\n * @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.\n * @property {OpenSeadragon.Tile} context - The HTML canvas context being drawn into.\n * @property {OpenSeadragon.Tile} rendered - The HTML canvas context containing the tile imagery.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n _this.viewer.raiseEvent('tile-drawing', $.extend({\n tiledImage: _this\n }, args));\n };\n};\n\n$.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.TiledImage.prototype */{\n /**\n * @returns {Boolean} Whether the TiledImage needs to be drawn.\n */\n needsDraw: function() {\n return this._needsDraw;\n },\n\n /**\n * @returns {Boolean} Whether all tiles necessary for this TiledImage to draw at the current view have been loaded.\n */\n getFullyLoaded: function() {\n return this._fullyLoaded;\n },\n\n // private\n _setFullyLoaded: function(flag) {\n if (flag === this._fullyLoaded) {\n return;\n }\n\n this._fullyLoaded = flag;\n\n /**\n * Fired when the TiledImage's \"fully loaded\" flag (whether all tiles necessary for this TiledImage\n * to draw at the current view have been loaded) changes.\n *\n * @event fully-loaded-change\n * @memberof OpenSeadragon.TiledImage\n * @type {object}\n * @property {Boolean} fullyLoaded - The new \"fully loaded\" value.\n * @property {OpenSeadragon.TiledImage} eventSource - A reference to the TiledImage which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent('fully-loaded-change', {\n fullyLoaded: this._fullyLoaded\n });\n },\n\n /**\n * Clears all tiles and triggers an update on the next call to\n * {@link OpenSeadragon.TiledImage#update}.\n */\n reset: function() {\n this._tileCache.clearTilesFor(this);\n this.lastResetTime = $.now();\n this._needsDraw = true;\n },\n\n /**\n * Updates the TiledImage's bounds, animating if needed.\n * @returns {Boolean} Whether the TiledImage animated.\n */\n update: function() {\n var xUpdated = this._xSpring.update();\n var yUpdated = this._ySpring.update();\n var scaleUpdated = this._scaleSpring.update();\n var degreesUpdated = this._degreesSpring.update();\n\n if (xUpdated || yUpdated || scaleUpdated || degreesUpdated) {\n this._updateForScale();\n this._needsDraw = true;\n return true;\n }\n\n return false;\n },\n\n /**\n * Draws the TiledImage to its Drawer.\n */\n draw: function() {\n if (this.opacity !== 0 || this._preload) {\n this._midDraw = true;\n this._updateViewport();\n this._midDraw = false;\n }\n },\n\n /**\n * Destroy the TiledImage (unload current loaded tiles).\n */\n destroy: function() {\n this.reset();\n },\n\n /**\n * Get this TiledImage's bounds in viewport coordinates.\n * @param {Boolean} [current=false] - Pass true for the current location;\n * false for target location.\n * @returns {OpenSeadragon.Rect} This TiledImage's bounds in viewport coordinates.\n */\n getBounds: function(current) {\n return this.getBoundsNoRotate(current)\n .rotate(this.getRotation(current), this._getRotationPoint(current));\n },\n\n /**\n * Get this TiledImage's bounds in viewport coordinates without taking\n * rotation into account.\n * @param {Boolean} [current=false] - Pass true for the current location;\n * false for target location.\n * @returns {OpenSeadragon.Rect} This TiledImage's bounds in viewport coordinates.\n */\n getBoundsNoRotate: function(current) {\n return current ?\n new $.Rect(\n this._xSpring.current.value,\n this._ySpring.current.value,\n this._worldWidthCurrent,\n this._worldHeightCurrent) :\n new $.Rect(\n this._xSpring.target.value,\n this._ySpring.target.value,\n this._worldWidthTarget,\n this._worldHeightTarget);\n },\n\n // deprecated\n getWorldBounds: function() {\n $.console.error('[TiledImage.getWorldBounds] is deprecated; use TiledImage.getBounds instead');\n return this.getBounds();\n },\n\n /**\n * Get the bounds of the displayed part of the tiled image.\n * @param {Boolean} [current=false] Pass true for the current location,\n * false for the target location.\n * @returns {$.Rect} The clipped bounds in viewport coordinates.\n */\n getClippedBounds: function(current) {\n var bounds = this.getBoundsNoRotate(current);\n if (this._clip) {\n var worldWidth = current ?\n this._worldWidthCurrent : this._worldWidthTarget;\n var ratio = worldWidth / this.source.dimensions.x;\n var clip = this._clip.times(ratio);\n bounds = new $.Rect(\n bounds.x + clip.x,\n bounds.y + clip.y,\n clip.width,\n clip.height);\n }\n return bounds.rotate(this.getRotation(current), this._getRotationPoint(current));\n },\n\n /**\n * @returns {OpenSeadragon.Point} This TiledImage's content size, in original pixels.\n */\n getContentSize: function() {\n return new $.Point(this.source.dimensions.x, this.source.dimensions.y);\n },\n\n // private\n _viewportToImageDelta: function( viewerX, viewerY, current ) {\n var scale = (current ? this._scaleSpring.current.value : this._scaleSpring.target.value);\n return new $.Point(viewerX * (this.source.dimensions.x / scale),\n viewerY * ((this.source.dimensions.y * this.contentAspectX) / scale));\n },\n\n /**\n * Translates from OpenSeadragon viewer coordinate system to image coordinate system.\n * This method can be called either by passing X,Y coordinates or an {@link OpenSeadragon.Point}.\n * @param {Number|OpenSeadragon.Point} viewerX - The X coordinate or point in viewport coordinate system.\n * @param {Number} [viewerY] - The Y coordinate in viewport coordinate system.\n * @param {Boolean} [current=false] - Pass true to use the current location; false for target location.\n * @return {OpenSeadragon.Point} A point representing the coordinates in the image.\n */\n viewportToImageCoordinates: function(viewerX, viewerY, current) {\n var point;\n if (viewerX instanceof $.Point) {\n //they passed a point instead of individual components\n current = viewerY;\n point = viewerX;\n } else {\n point = new $.Point(viewerX, viewerY);\n }\n\n point = point.rotate(-this.getRotation(current), this._getRotationPoint(current));\n return current ?\n this._viewportToImageDelta(\n point.x - this._xSpring.current.value,\n point.y - this._ySpring.current.value) :\n this._viewportToImageDelta(\n point.x - this._xSpring.target.value,\n point.y - this._ySpring.target.value);\n },\n\n // private\n _imageToViewportDelta: function( imageX, imageY, current ) {\n var scale = (current ? this._scaleSpring.current.value : this._scaleSpring.target.value);\n return new $.Point((imageX / this.source.dimensions.x) * scale,\n (imageY / this.source.dimensions.y / this.contentAspectX) * scale);\n },\n\n /**\n * Translates from image coordinate system to OpenSeadragon viewer coordinate system\n * This method can be called either by passing X,Y coordinates or an {@link OpenSeadragon.Point}.\n * @param {Number|OpenSeadragon.Point} imageX - The X coordinate or point in image coordinate system.\n * @param {Number} [imageY] - The Y coordinate in image coordinate system.\n * @param {Boolean} [current=false] - Pass true to use the current location; false for target location.\n * @return {OpenSeadragon.Point} A point representing the coordinates in the viewport.\n */\n imageToViewportCoordinates: function(imageX, imageY, current) {\n if (imageX instanceof $.Point) {\n //they passed a point instead of individual components\n current = imageY;\n imageY = imageX.y;\n imageX = imageX.x;\n }\n\n var point = this._imageToViewportDelta(imageX, imageY);\n if (current) {\n point.x += this._xSpring.current.value;\n point.y += this._ySpring.current.value;\n } else {\n point.x += this._xSpring.target.value;\n point.y += this._ySpring.target.value;\n }\n\n return point.rotate(this.getRotation(current), this._getRotationPoint(current));\n },\n\n /**\n * Translates from a rectangle which describes a portion of the image in\n * pixel coordinates to OpenSeadragon viewport rectangle coordinates.\n * This method can be called either by passing X,Y,width,height or an {@link OpenSeadragon.Rect}.\n * @param {Number|OpenSeadragon.Rect} imageX - The left coordinate or rectangle in image coordinate system.\n * @param {Number} [imageY] - The top coordinate in image coordinate system.\n * @param {Number} [pixelWidth] - The width in pixel of the rectangle.\n * @param {Number} [pixelHeight] - The height in pixel of the rectangle.\n * @param {Boolean} [current=false] - Pass true to use the current location; false for target location.\n * @return {OpenSeadragon.Rect} A rect representing the coordinates in the viewport.\n */\n imageToViewportRectangle: function(imageX, imageY, pixelWidth, pixelHeight, current) {\n var rect = imageX;\n if (rect instanceof $.Rect) {\n //they passed a rect instead of individual components\n current = imageY;\n } else {\n rect = new $.Rect(imageX, imageY, pixelWidth, pixelHeight);\n }\n\n var coordA = this.imageToViewportCoordinates(rect.getTopLeft(), current);\n var coordB = this._imageToViewportDelta(rect.width, rect.height, current);\n\n return new $.Rect(\n coordA.x,\n coordA.y,\n coordB.x,\n coordB.y,\n rect.degrees + this.getRotation(current)\n );\n },\n\n /**\n * Translates from a rectangle which describes a portion of\n * the viewport in point coordinates to image rectangle coordinates.\n * This method can be called either by passing X,Y,width,height or an {@link OpenSeadragon.Rect}.\n * @param {Number|OpenSeadragon.Rect} viewerX - The left coordinate or rectangle in viewport coordinate system.\n * @param {Number} [viewerY] - The top coordinate in viewport coordinate system.\n * @param {Number} [pointWidth] - The width in viewport coordinate system.\n * @param {Number} [pointHeight] - The height in viewport coordinate system.\n * @param {Boolean} [current=false] - Pass true to use the current location; false for target location.\n * @return {OpenSeadragon.Rect} A rect representing the coordinates in the image.\n */\n viewportToImageRectangle: function( viewerX, viewerY, pointWidth, pointHeight, current ) {\n var rect = viewerX;\n if (viewerX instanceof $.Rect) {\n //they passed a rect instead of individual components\n current = viewerY;\n } else {\n rect = new $.Rect(viewerX, viewerY, pointWidth, pointHeight);\n }\n\n var coordA = this.viewportToImageCoordinates(rect.getTopLeft(), current);\n var coordB = this._viewportToImageDelta(rect.width, rect.height, current);\n\n return new $.Rect(\n coordA.x,\n coordA.y,\n coordB.x,\n coordB.y,\n rect.degrees - this.getRotation(current)\n );\n },\n\n /**\n * Convert pixel coordinates relative to the viewer element to image\n * coordinates.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n viewerElementToImageCoordinates: function( pixel ) {\n var point = this.viewport.pointFromPixel( pixel, true );\n return this.viewportToImageCoordinates( point );\n },\n\n /**\n * Convert pixel coordinates relative to the image to\n * viewer element coordinates.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n imageToViewerElementCoordinates: function( pixel ) {\n var point = this.imageToViewportCoordinates( pixel );\n return this.viewport.pixelFromPoint( point, true );\n },\n\n /**\n * Convert pixel coordinates relative to the window to image coordinates.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n windowToImageCoordinates: function( pixel ) {\n var viewerCoordinates = pixel.minus(\n OpenSeadragon.getElementPosition( this.viewer.element ));\n return this.viewerElementToImageCoordinates( viewerCoordinates );\n },\n\n /**\n * Convert image coordinates to pixel coordinates relative to the window.\n * @param {OpenSeadragon.Point} pixel\n * @returns {OpenSeadragon.Point}\n */\n imageToWindowCoordinates: function( pixel ) {\n var viewerCoordinates = this.imageToViewerElementCoordinates( pixel );\n return viewerCoordinates.plus(\n OpenSeadragon.getElementPosition( this.viewer.element ));\n },\n\n // private\n // Convert rectangle in viewport coordinates to this tiled image point\n // coordinates (x in [0, 1] and y in [0, aspectRatio])\n _viewportToTiledImageRectangle: function(rect) {\n var scale = this._scaleSpring.current.value;\n rect = rect.rotate(-this.getRotation(true), this._getRotationPoint(true));\n return new $.Rect(\n (rect.x - this._xSpring.current.value) / scale,\n (rect.y - this._ySpring.current.value) / scale,\n rect.width / scale,\n rect.height / scale,\n rect.degrees);\n },\n\n /**\n * Convert a viewport zoom to an image zoom.\n * Image zoom: ratio of the original image size to displayed image size.\n * 1 means original image size, 0.5 half size...\n * Viewport zoom: ratio of the displayed image's width to viewport's width.\n * 1 means identical width, 2 means image's width is twice the viewport's width...\n * @function\n * @param {Number} viewportZoom The viewport zoom\n * @returns {Number} imageZoom The image zoom\n */\n viewportToImageZoom: function( viewportZoom ) {\n var ratio = this._scaleSpring.current.value *\n this.viewport._containerInnerSize.x / this.source.dimensions.x;\n return ratio * viewportZoom;\n },\n\n /**\n * Convert an image zoom to a viewport zoom.\n * Image zoom: ratio of the original image size to displayed image size.\n * 1 means original image size, 0.5 half size...\n * Viewport zoom: ratio of the displayed image's width to viewport's width.\n * 1 means identical width, 2 means image's width is twice the viewport's width...\n * Note: not accurate with multi-image.\n * @function\n * @param {Number} imageZoom The image zoom\n * @returns {Number} viewportZoom The viewport zoom\n */\n imageToViewportZoom: function( imageZoom ) {\n var ratio = this._scaleSpring.current.value *\n this.viewport._containerInnerSize.x / this.source.dimensions.x;\n return imageZoom / ratio;\n },\n\n /**\n * Sets the TiledImage's position in the world.\n * @param {OpenSeadragon.Point} position - The new position, in viewport coordinates.\n * @param {Boolean} [immediately=false] - Whether to animate to the new position or snap immediately.\n * @fires OpenSeadragon.TiledImage.event:bounds-change\n */\n setPosition: function(position, immediately) {\n var sameTarget = (this._xSpring.target.value === position.x &&\n this._ySpring.target.value === position.y);\n\n if (immediately) {\n if (sameTarget && this._xSpring.current.value === position.x &&\n this._ySpring.current.value === position.y) {\n return;\n }\n\n this._xSpring.resetTo(position.x);\n this._ySpring.resetTo(position.y);\n this._needsDraw = true;\n } else {\n if (sameTarget) {\n return;\n }\n\n this._xSpring.springTo(position.x);\n this._ySpring.springTo(position.y);\n this._needsDraw = true;\n }\n\n if (!sameTarget) {\n this._raiseBoundsChange();\n }\n },\n\n /**\n * Sets the TiledImage's width in the world, adjusting the height to match based on aspect ratio.\n * @param {Number} width - The new width, in viewport coordinates.\n * @param {Boolean} [immediately=false] - Whether to animate to the new size or snap immediately.\n * @fires OpenSeadragon.TiledImage.event:bounds-change\n */\n setWidth: function(width, immediately) {\n this._setScale(width, immediately);\n },\n\n /**\n * Sets the TiledImage's height in the world, adjusting the width to match based on aspect ratio.\n * @param {Number} height - The new height, in viewport coordinates.\n * @param {Boolean} [immediately=false] - Whether to animate to the new size or snap immediately.\n * @fires OpenSeadragon.TiledImage.event:bounds-change\n */\n setHeight: function(height, immediately) {\n this._setScale(height / this.normHeight, immediately);\n },\n\n /**\n * Positions and scales the TiledImage to fit in the specified bounds.\n * Note: this method fires OpenSeadragon.TiledImage.event:bounds-change\n * twice\n * @param {OpenSeadragon.Rect} bounds The bounds to fit the image into.\n * @param {OpenSeadragon.Placement} [anchor=OpenSeadragon.Placement.CENTER]\n * How to anchor the image in the bounds.\n * @param {Boolean} [immediately=false] Whether to animate to the new size\n * or snap immediately.\n * @fires OpenSeadragon.TiledImage.event:bounds-change\n */\n fitBounds: function(bounds, anchor, immediately) {\n anchor = anchor || $.Placement.CENTER;\n var anchorProperties = $.Placement.properties[anchor];\n var aspectRatio = this.contentAspectX;\n var xOffset = 0;\n var yOffset = 0;\n var displayedWidthRatio = 1;\n var displayedHeightRatio = 1;\n if (this._clip) {\n aspectRatio = this._clip.getAspectRatio();\n displayedWidthRatio = this._clip.width / this.source.dimensions.x;\n displayedHeightRatio = this._clip.height / this.source.dimensions.y;\n if (bounds.getAspectRatio() > aspectRatio) {\n xOffset = this._clip.x / this._clip.height * bounds.height;\n yOffset = this._clip.y / this._clip.height * bounds.height;\n } else {\n xOffset = this._clip.x / this._clip.width * bounds.width;\n yOffset = this._clip.y / this._clip.width * bounds.width;\n }\n }\n\n if (bounds.getAspectRatio() > aspectRatio) {\n // We will have margins on the X axis\n var height = bounds.height / displayedHeightRatio;\n var marginLeft = 0;\n if (anchorProperties.isHorizontallyCentered) {\n marginLeft = (bounds.width - bounds.height * aspectRatio) / 2;\n } else if (anchorProperties.isRight) {\n marginLeft = bounds.width - bounds.height * aspectRatio;\n }\n this.setPosition(\n new $.Point(bounds.x - xOffset + marginLeft, bounds.y - yOffset),\n immediately);\n this.setHeight(height, immediately);\n } else {\n // We will have margins on the Y axis\n var width = bounds.width / displayedWidthRatio;\n var marginTop = 0;\n if (anchorProperties.isVerticallyCentered) {\n marginTop = (bounds.height - bounds.width / aspectRatio) / 2;\n } else if (anchorProperties.isBottom) {\n marginTop = bounds.height - bounds.width / aspectRatio;\n }\n this.setPosition(\n new $.Point(bounds.x - xOffset, bounds.y - yOffset + marginTop),\n immediately);\n this.setWidth(width, immediately);\n }\n },\n\n /**\n * @returns {OpenSeadragon.Rect|null} The TiledImage's current clip rectangle,\n * in image pixels, or null if none.\n */\n getClip: function() {\n if (this._clip) {\n return this._clip.clone();\n }\n\n return null;\n },\n\n /**\n * @param {OpenSeadragon.Rect|null} newClip - An area, in image pixels, to clip to\n * (portions of the image outside of this area will not be visible). Only works on\n * browsers that support the HTML5 canvas.\n * @fires OpenSeadragon.TiledImage.event:clip-change\n */\n setClip: function(newClip) {\n $.console.assert(!newClip || newClip instanceof $.Rect,\n \"[TiledImage.setClip] newClip must be an OpenSeadragon.Rect or null\");\n\n if (newClip instanceof $.Rect) {\n this._clip = newClip.clone();\n } else {\n this._clip = null;\n }\n\n this._needsDraw = true;\n /**\n * Raised when the TiledImage's clip is changed.\n * @event clip-change\n * @memberOf OpenSeadragon.TiledImage\n * @type {object}\n * @property {OpenSeadragon.TiledImage} eventSource - A reference to the\n * TiledImage which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent('clip-change');\n },\n\n /**\n * @returns {Number} The TiledImage's current opacity.\n */\n getOpacity: function() {\n return this.opacity;\n },\n\n /**\n * @param {Number} opacity Opacity the tiled image should be drawn at.\n * @fires OpenSeadragon.TiledImage.event:opacity-change\n */\n setOpacity: function(opacity) {\n if (opacity === this.opacity) {\n return;\n }\n\n this.opacity = opacity;\n this._needsDraw = true;\n /**\n * Raised when the TiledImage's opacity is changed.\n * @event opacity-change\n * @memberOf OpenSeadragon.TiledImage\n * @type {object}\n * @property {Number} opacity - The new opacity value.\n * @property {OpenSeadragon.TiledImage} eventSource - A reference to the\n * TiledImage which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent('opacity-change', {\n opacity: this.opacity\n });\n },\n\n /**\n * @returns {Boolean} whether the tiledImage can load its tiles even when it has zero opacity.\n */\n getPreload: function() {\n return this._preload;\n },\n\n /**\n * Set true to load even when hidden. Set false to block loading when hidden.\n */\n setPreload: function(preload) {\n this._preload = !!preload;\n this._needsDraw = true;\n },\n\n /**\n * Get the rotation of this tiled image in degrees.\n * @param {Boolean} [current=false] True for current rotation, false for target.\n * @returns {Number} the rotation of this tiled image in degrees.\n */\n getRotation: function(current) {\n return current ?\n this._degreesSpring.current.value :\n this._degreesSpring.target.value;\n },\n\n /**\n * Set the current rotation of this tiled image in degrees.\n * @param {Number} degrees the rotation in degrees.\n * @param {Boolean} [immediately=false] Whether to animate to the new angle\n * or rotate immediately.\n * @fires OpenSeadragon.TiledImage.event:bounds-change\n */\n setRotation: function(degrees, immediately) {\n if (this._degreesSpring.target.value === degrees &&\n this._degreesSpring.isAtTargetValue()) {\n return;\n }\n if (immediately) {\n this._degreesSpring.resetTo(degrees);\n } else {\n this._degreesSpring.springTo(degrees);\n }\n this._needsDraw = true;\n this._raiseBoundsChange();\n },\n\n /**\n * Get the point around which this tiled image is rotated\n * @private\n * @param {Boolean} current True for current rotation point, false for target.\n * @returns {OpenSeadragon.Point}\n */\n _getRotationPoint: function(current) {\n return this.getBoundsNoRotate(current).getCenter();\n },\n\n /**\n * @returns {String} The TiledImage's current compositeOperation.\n */\n getCompositeOperation: function() {\n return this.compositeOperation;\n },\n\n /**\n * @param {String} compositeOperation the tiled image should be drawn with this globalCompositeOperation.\n * @fires OpenSeadragon.TiledImage.event:composite-operation-change\n */\n setCompositeOperation: function(compositeOperation) {\n if (compositeOperation === this.compositeOperation) {\n return;\n }\n\n this.compositeOperation = compositeOperation;\n this._needsDraw = true;\n /**\n * Raised when the TiledImage's opacity is changed.\n * @event composite-operation-change\n * @memberOf OpenSeadragon.TiledImage\n * @type {object}\n * @property {String} compositeOperation - The new compositeOperation value.\n * @property {OpenSeadragon.TiledImage} eventSource - A reference to the\n * TiledImage which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent('composite-operation-change', {\n compositeOperation: this.compositeOperation\n });\n },\n\n // private\n _setScale: function(scale, immediately) {\n var sameTarget = (this._scaleSpring.target.value === scale);\n if (immediately) {\n if (sameTarget && this._scaleSpring.current.value === scale) {\n return;\n }\n\n this._scaleSpring.resetTo(scale);\n this._updateForScale();\n this._needsDraw = true;\n } else {\n if (sameTarget) {\n return;\n }\n\n this._scaleSpring.springTo(scale);\n this._updateForScale();\n this._needsDraw = true;\n }\n\n if (!sameTarget) {\n this._raiseBoundsChange();\n }\n },\n\n // private\n _updateForScale: function() {\n this._worldWidthTarget = this._scaleSpring.target.value;\n this._worldHeightTarget = this.normHeight * this._scaleSpring.target.value;\n this._worldWidthCurrent = this._scaleSpring.current.value;\n this._worldHeightCurrent = this.normHeight * this._scaleSpring.current.value;\n },\n\n // private\n _raiseBoundsChange: function() {\n /**\n * Raised when the TiledImage's bounds are changed.\n * Note that this event is triggered only when the animation target is changed;\n * not for every frame of animation.\n * @event bounds-change\n * @memberOf OpenSeadragon.TiledImage\n * @type {object}\n * @property {OpenSeadragon.TiledImage} eventSource - A reference to the\n * TiledImage which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent('bounds-change');\n },\n\n // private\n _isBottomItem: function() {\n return this.viewer.world.getItemAt(0) === this;\n },\n\n // private\n _getLevelsInterval: function() {\n var lowestLevel = Math.max(\n this.source.minLevel,\n Math.floor(Math.log(this.minZoomImageRatio) / Math.log(2))\n );\n var currentZeroRatio = this.viewport.deltaPixelsFromPointsNoRotate(\n this.source.getPixelRatio(0), true).x *\n this._scaleSpring.current.value;\n var highestLevel = Math.min(\n Math.abs(this.source.maxLevel),\n Math.abs(Math.floor(\n Math.log(currentZeroRatio / this.minPixelRatio) / Math.log(2)\n ))\n );\n\n // Calculations for the interval of levels to draw\n // can return invalid intervals; fix that here if necessary\n lowestLevel = Math.min(lowestLevel, highestLevel);\n return {\n lowestLevel: lowestLevel,\n highestLevel: highestLevel\n };\n },\n\n /**\n * @private\n * @inner\n * Pretty much every other line in this needs to be documented so it's clear\n * how each piece of this routine contributes to the drawing process. That's\n * why there are so many TODO's inside this function.\n */\n _updateViewport: function() {\n this._needsDraw = false;\n this._tilesLoading = 0;\n this.loadingCoverage = {};\n\n // Reset tile's internal drawn state\n while (this.lastDrawn.length > 0) {\n var tile = this.lastDrawn.pop();\n tile.beingDrawn = false;\n }\n\n var viewport = this.viewport;\n var drawArea = this._viewportToTiledImageRectangle(\n viewport.getBoundsWithMargins(true));\n\n if (!this.wrapHorizontal && !this.wrapVertical) {\n var tiledImageBounds = this._viewportToTiledImageRectangle(\n this.getClippedBounds(true));\n drawArea = drawArea.intersection(tiledImageBounds);\n if (drawArea === null) {\n return;\n }\n }\n\n var levelsInterval = this._getLevelsInterval();\n var lowestLevel = levelsInterval.lowestLevel;\n var highestLevel = levelsInterval.highestLevel;\n var bestTile = null;\n var haveDrawn = false;\n var currentTime = $.now();\n\n // Update any level that will be drawn\n for (var level = highestLevel; level >= lowestLevel; level--) {\n var drawLevel = false;\n\n //Avoid calculations for draw if we have already drawn this\n var currentRenderPixelRatio = viewport.deltaPixelsFromPointsNoRotate(\n this.source.getPixelRatio(level),\n true\n ).x * this._scaleSpring.current.value;\n\n if (level === lowestLevel ||\n (!haveDrawn && currentRenderPixelRatio >= this.minPixelRatio)) {\n drawLevel = true;\n haveDrawn = true;\n } else if (!haveDrawn) {\n continue;\n }\n\n //Perform calculations for draw if we haven't drawn this\n var targetRenderPixelRatio = viewport.deltaPixelsFromPointsNoRotate(\n this.source.getPixelRatio(level),\n false\n ).x * this._scaleSpring.current.value;\n\n var targetZeroRatio = viewport.deltaPixelsFromPointsNoRotate(\n this.source.getPixelRatio(\n Math.max(\n this.source.getClosestLevel(),\n 0\n )\n ),\n false\n ).x * this._scaleSpring.current.value;\n\n var optimalRatio = this.immediateRender ? 1 : targetZeroRatio;\n var levelOpacity = Math.min(1, (currentRenderPixelRatio - 0.5) / 0.5);\n var levelVisibility = optimalRatio / Math.abs(\n optimalRatio - targetRenderPixelRatio\n );\n\n // Update the level and keep track of 'best' tile to load\n bestTile = updateLevel(\n this,\n haveDrawn,\n drawLevel,\n level,\n levelOpacity,\n levelVisibility,\n drawArea,\n currentTime,\n bestTile\n );\n\n // Stop the loop if lower-res tiles would all be covered by\n // already drawn tiles\n if (providesCoverage(this.coverage, level)) {\n break;\n }\n }\n\n // Perform the actual drawing\n drawTiles(this, this.lastDrawn);\n\n // Load the new 'best' tile\n if (bestTile && !bestTile.context2D) {\n loadTile(this, bestTile, currentTime);\n this._needsDraw = true;\n this._setFullyLoaded(false);\n } else {\n this._setFullyLoaded(this._tilesLoading === 0);\n }\n },\n\n // private\n _getCornerTiles: function(level, topLeftBound, bottomRightBound) {\n var leftX;\n var rightX;\n if (this.wrapHorizontal) {\n leftX = $.positiveModulo(topLeftBound.x, 1);\n rightX = $.positiveModulo(bottomRightBound.x, 1);\n } else {\n leftX = Math.max(0, topLeftBound.x);\n rightX = Math.min(1, bottomRightBound.x);\n }\n var topY;\n var bottomY;\n var aspectRatio = 1 / this.source.aspectRatio;\n if (this.wrapVertical) {\n topY = $.positiveModulo(topLeftBound.y, aspectRatio);\n bottomY = $.positiveModulo(bottomRightBound.y, aspectRatio);\n } else {\n topY = Math.max(0, topLeftBound.y);\n bottomY = Math.min(aspectRatio, bottomRightBound.y);\n }\n\n var topLeftTile = this.source.getTileAtPoint(level, new $.Point(leftX, topY));\n var bottomRightTile = this.source.getTileAtPoint(level, new $.Point(rightX, bottomY));\n var numTiles = this.source.getNumTiles(level);\n\n if (this.wrapHorizontal) {\n topLeftTile.x += numTiles.x * Math.floor(topLeftBound.x);\n bottomRightTile.x += numTiles.x * Math.floor(bottomRightBound.x);\n }\n if (this.wrapVertical) {\n topLeftTile.y += numTiles.y * Math.floor(topLeftBound.y / aspectRatio);\n bottomRightTile.y += numTiles.y * Math.floor(bottomRightBound.y / aspectRatio);\n }\n\n return {\n topLeft: topLeftTile,\n bottomRight: bottomRightTile,\n };\n }\n});\n\n/**\n * @private\n * @inner\n * Updates all tiles at a given resolution level.\n * @param {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.\n * @param {Boolean} haveDrawn\n * @param {Boolean} drawLevel\n * @param {Number} level\n * @param {Number} levelOpacity\n * @param {Number} levelVisibility\n * @param {OpenSeadragon.Point} viewportTL - The index of the most top-left visible tile.\n * @param {OpenSeadragon.Point} viewportBR - The index of the most bottom-right visible tile.\n * @param {Number} currentTime\n * @param {OpenSeadragon.Tile} best - The current \"best\" tile to draw.\n */\nfunction updateLevel(tiledImage, haveDrawn, drawLevel, level, levelOpacity,\n levelVisibility, drawArea, currentTime, best) {\n\n var topLeftBound = drawArea.getBoundingBox().getTopLeft();\n var bottomRightBound = drawArea.getBoundingBox().getBottomRight();\n\n if (tiledImage.viewer) {\n /**\n * - Needs documentation -\n *\n * @event update-level\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.\n * @property {Object} havedrawn\n * @property {Object} level\n * @property {Object} opacity\n * @property {Object} visibility\n * @property {OpenSeadragon.Rect} drawArea\n * @property {Object} topleft deprecated, use drawArea instead\n * @property {Object} bottomright deprecated, use drawArea instead\n * @property {Object} currenttime\n * @property {Object} best\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n tiledImage.viewer.raiseEvent('update-level', {\n tiledImage: tiledImage,\n havedrawn: haveDrawn,\n level: level,\n opacity: levelOpacity,\n visibility: levelVisibility,\n drawArea: drawArea,\n topleft: topLeftBound,\n bottomright: bottomRightBound,\n currenttime: currentTime,\n best: best\n });\n }\n\n resetCoverage(tiledImage.coverage, level);\n resetCoverage(tiledImage.loadingCoverage, level);\n\n //OK, a new drawing so do your calculations\n var cornerTiles = tiledImage._getCornerTiles(level, topLeftBound, bottomRightBound);\n var topLeftTile = cornerTiles.topLeft;\n var bottomRightTile = cornerTiles.bottomRight;\n var numberOfTiles = tiledImage.source.getNumTiles(level);\n\n var viewportCenter = tiledImage.viewport.pixelFromPoint(\n tiledImage.viewport.getCenter());\n for (var x = topLeftTile.x; x <= bottomRightTile.x; x++) {\n for (var y = topLeftTile.y; y <= bottomRightTile.y; y++) {\n\n // Optimisation disabled with wrapping because getTileBounds does not\n // work correctly with x and y outside of the number of tiles\n if (!tiledImage.wrapHorizontal && !tiledImage.wrapVertical) {\n var tileBounds = tiledImage.source.getTileBounds(level, x, y);\n if (drawArea.intersection(tileBounds) === null) {\n // This tile is outside of the viewport, no need to draw it\n continue;\n }\n }\n\n best = updateTile(\n tiledImage,\n drawLevel,\n haveDrawn,\n x, y,\n level,\n levelOpacity,\n levelVisibility,\n viewportCenter,\n numberOfTiles,\n currentTime,\n best\n );\n\n }\n }\n\n return best;\n}\n\n/**\n * @private\n * @inner\n * Update a single tile at a particular resolution level.\n * @param {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.\n * @param {Boolean} haveDrawn\n * @param {Boolean} drawLevel\n * @param {Number} x\n * @param {Number} y\n * @param {Number} level\n * @param {Number} levelOpacity\n * @param {Number} levelVisibility\n * @param {OpenSeadragon.Point} viewportCenter\n * @param {Number} numberOfTiles\n * @param {Number} currentTime\n * @param {OpenSeadragon.Tile} best - The current \"best\" tile to draw.\n */\nfunction updateTile( tiledImage, haveDrawn, drawLevel, x, y, level, levelOpacity, levelVisibility, viewportCenter, numberOfTiles, currentTime, best){\n\n var tile = getTile(\n x, y,\n level,\n tiledImage,\n tiledImage.source,\n tiledImage.tilesMatrix,\n currentTime,\n numberOfTiles,\n tiledImage._worldWidthCurrent,\n tiledImage._worldHeightCurrent\n ),\n drawTile = drawLevel;\n\n if( tiledImage.viewer ){\n /**\n * - Needs documentation -\n *\n * @event update-tile\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.\n * @property {OpenSeadragon.Tile} tile\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n tiledImage.viewer.raiseEvent( 'update-tile', {\n tiledImage: tiledImage,\n tile: tile\n });\n }\n\n setCoverage( tiledImage.coverage, level, x, y, false );\n\n var loadingCoverage = tile.loaded || tile.loading || isCovered(tiledImage.loadingCoverage, level, x, y);\n setCoverage(tiledImage.loadingCoverage, level, x, y, loadingCoverage);\n\n if ( !tile.exists ) {\n return best;\n }\n\n if ( haveDrawn && !drawTile ) {\n if ( isCovered( tiledImage.coverage, level, x, y ) ) {\n setCoverage( tiledImage.coverage, level, x, y, true );\n } else {\n drawTile = true;\n }\n }\n\n if ( !drawTile ) {\n return best;\n }\n\n positionTile(\n tile,\n tiledImage.source.tileOverlap,\n tiledImage.viewport,\n viewportCenter,\n levelVisibility,\n tiledImage\n );\n\n if (!tile.loaded) {\n if (tile.context2D) {\n setTileLoaded(tiledImage, tile);\n } else {\n var imageRecord = tiledImage._tileCache.getImageRecord(tile.cacheKey);\n if (imageRecord) {\n var image = imageRecord.getImage();\n setTileLoaded(tiledImage, tile, image);\n }\n }\n }\n\n if ( tile.loaded ) {\n var needsDraw = blendTile(\n tiledImage,\n tile,\n x, y,\n level,\n levelOpacity,\n currentTime\n );\n\n if ( needsDraw ) {\n tiledImage._needsDraw = true;\n }\n } else if ( tile.loading ) {\n // the tile is already in the download queue\n tiledImage._tilesLoading++;\n } else if (!loadingCoverage) {\n best = compareTiles( best, tile );\n }\n\n return best;\n}\n\n/**\n * @private\n * @inner\n * Obtains a tile at the given location.\n * @param {Number} x\n * @param {Number} y\n * @param {Number} level\n * @param {OpenSeadragon.TiledImage} tiledImage\n * @param {OpenSeadragon.TileSource} tileSource\n * @param {Object} tilesMatrix - A '3d' dictionary [level][x][y] --> Tile.\n * @param {Number} time\n * @param {Number} numTiles\n * @param {Number} worldWidth\n * @param {Number} worldHeight\n * @returns {OpenSeadragon.Tile}\n */\nfunction getTile(\n x, y,\n level,\n tiledImage,\n tileSource,\n tilesMatrix,\n time,\n numTiles,\n worldWidth,\n worldHeight\n) {\n var xMod,\n yMod,\n bounds,\n exists,\n url,\n ajaxHeaders,\n context2D,\n tile;\n\n if ( !tilesMatrix[ level ] ) {\n tilesMatrix[ level ] = {};\n }\n if ( !tilesMatrix[ level ][ x ] ) {\n tilesMatrix[ level ][ x ] = {};\n }\n\n if ( !tilesMatrix[ level ][ x ][ y ] ) {\n xMod = ( numTiles.x + ( x % numTiles.x ) ) % numTiles.x;\n yMod = ( numTiles.y + ( y % numTiles.y ) ) % numTiles.y;\n bounds = tileSource.getTileBounds( level, xMod, yMod );\n exists = tileSource.tileExists( level, xMod, yMod );\n url = tileSource.getTileUrl( level, xMod, yMod );\n\n // Headers are only applicable if loadTilesWithAjax is set\n if (tiledImage.loadTilesWithAjax) {\n ajaxHeaders = tileSource.getTileAjaxHeaders( level, xMod, yMod );\n // Combine tile AJAX headers with tiled image AJAX headers (if applicable)\n if ($.isPlainObject(tiledImage.ajaxHeaders)) {\n ajaxHeaders = $.extend({}, tiledImage.ajaxHeaders, ajaxHeaders);\n }\n } else {\n ajaxHeaders = null;\n }\n\n context2D = tileSource.getContext2D ?\n tileSource.getContext2D(level, xMod, yMod) : undefined;\n\n bounds.x += ( x - xMod ) / numTiles.x;\n bounds.y += (worldHeight / worldWidth) * (( y - yMod ) / numTiles.y);\n\n tile = new $.Tile(\n level,\n x,\n y,\n bounds,\n exists,\n url,\n context2D,\n tiledImage.loadTilesWithAjax,\n ajaxHeaders\n );\n\n if (xMod === numTiles.x - 1) {\n tile.isRightMost = true;\n }\n\n if (yMod === numTiles.y - 1) {\n tile.isBottomMost = true;\n }\n\n tilesMatrix[ level ][ x ][ y ] = tile;\n }\n\n tile = tilesMatrix[ level ][ x ][ y ];\n tile.lastTouchTime = time;\n\n return tile;\n}\n\n/**\n * @private\n * @inner\n * Dispatch a job to the ImageLoader to load the Image for a Tile.\n * @param {OpenSeadragon.TiledImage} tiledImage\n * @param {OpenSeadragon.Tile} tile\n * @param {Number} time\n */\nfunction loadTile( tiledImage, tile, time ) {\n tile.loading = true;\n tiledImage._imageLoader.addJob({\n src: tile.url,\n loadWithAjax: tile.loadWithAjax,\n ajaxHeaders: tile.ajaxHeaders,\n crossOriginPolicy: tiledImage.crossOriginPolicy,\n ajaxWithCredentials: tiledImage.ajaxWithCredentials,\n callback: function( image, errorMsg, tileRequest ){\n onTileLoad( tiledImage, tile, time, image, errorMsg, tileRequest );\n },\n abort: function() {\n tile.loading = false;\n }\n });\n}\n\n/**\n * @private\n * @inner\n * Callback fired when a Tile's Image finished downloading.\n * @param {OpenSeadragon.TiledImage} tiledImage\n * @param {OpenSeadragon.Tile} tile\n * @param {Number} time\n * @param {Image} image\n * @param {String} errorMsg\n * @param {XMLHttpRequest} tileRequest\n */\nfunction onTileLoad( tiledImage, tile, time, image, errorMsg, tileRequest ) {\n if ( !image ) {\n $.console.log( \"Tile %s failed to load: %s - error: %s\", tile, tile.url, errorMsg );\n /**\n * Triggered when a tile fails to load.\n *\n * @event tile-load-failed\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Tile} tile - The tile that failed to load.\n * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image the tile belongs to.\n * @property {number} time - The time in milliseconds when the tile load began.\n * @property {string} message - The error message.\n * @property {XMLHttpRequest} tileRequest - The XMLHttpRequest used to load the tile if available.\n */\n tiledImage.viewer.raiseEvent(\"tile-load-failed\", {\n tile: tile,\n tiledImage: tiledImage,\n time: time,\n message: errorMsg,\n tileRequest: tileRequest\n });\n tile.loading = false;\n tile.exists = false;\n return;\n }\n\n if ( time < tiledImage.lastResetTime ) {\n $.console.log( \"Ignoring tile %s loaded before reset: %s\", tile, tile.url );\n tile.loading = false;\n return;\n }\n\n var finish = function() {\n var cutoff = tiledImage.source.getClosestLevel();\n setTileLoaded(tiledImage, tile, image, cutoff, tileRequest);\n };\n\n // Check if we're mid-update; this can happen on IE8 because image load events for\n // cached images happen immediately there\n if ( !tiledImage._midDraw ) {\n finish();\n } else {\n // Wait until after the update, in case caching unloads any tiles\n window.setTimeout( finish, 1);\n }\n}\n\n/**\n * @private\n * @inner\n * @param {OpenSeadragon.TiledImage} tiledImage\n * @param {OpenSeadragon.Tile} tile\n * @param {Image} image\n * @param {Number} cutoff\n */\nfunction setTileLoaded(tiledImage, tile, image, cutoff, tileRequest) {\n var increment = 0;\n\n function getCompletionCallback() {\n increment++;\n return completionCallback;\n }\n\n function completionCallback() {\n increment--;\n if (increment === 0) {\n tile.loading = false;\n tile.loaded = true;\n if (!tile.context2D) {\n tiledImage._tileCache.cacheTile({\n image: image,\n tile: tile,\n cutoff: cutoff,\n tiledImage: tiledImage\n });\n }\n tiledImage._needsDraw = true;\n }\n }\n\n /**\n * Triggered when a tile has just been loaded in memory. That means that the\n * image has been downloaded and can be modified before being drawn to the canvas.\n *\n * @event tile-loaded\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {Image} image - The image of the tile.\n * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image of the loaded tile.\n * @property {OpenSeadragon.Tile} tile - The tile which has been loaded.\n * @property {XMLHttpRequest} tiledImage - The AJAX request that loaded this tile (if applicable).\n * @property {function} getCompletionCallback - A function giving a callback to call\n * when the asynchronous processing of the image is done. The image will be\n * marked as entirely loaded when the callback has been called once for each\n * call to getCompletionCallback.\n */\n tiledImage.viewer.raiseEvent(\"tile-loaded\", {\n tile: tile,\n tiledImage: tiledImage,\n tileRequest: tileRequest,\n image: image,\n getCompletionCallback: getCompletionCallback\n });\n // In case the completion callback is never called, we at least force it once.\n getCompletionCallback()();\n}\n\n/**\n * @private\n * @inner\n * @param {OpenSeadragon.Tile} tile\n * @param {Boolean} overlap\n * @param {OpenSeadragon.Viewport} viewport\n * @param {OpenSeadragon.Point} viewportCenter\n * @param {Number} levelVisibility\n * @param {OpenSeadragon.TiledImage} tiledImage\n */\nfunction positionTile( tile, overlap, viewport, viewportCenter, levelVisibility, tiledImage ){\n var boundsTL = tile.bounds.getTopLeft();\n\n boundsTL.x *= tiledImage._scaleSpring.current.value;\n boundsTL.y *= tiledImage._scaleSpring.current.value;\n boundsTL.x += tiledImage._xSpring.current.value;\n boundsTL.y += tiledImage._ySpring.current.value;\n\n var boundsSize = tile.bounds.getSize();\n\n boundsSize.x *= tiledImage._scaleSpring.current.value;\n boundsSize.y *= tiledImage._scaleSpring.current.value;\n\n var positionC = viewport.pixelFromPointNoRotate(boundsTL, true),\n positionT = viewport.pixelFromPointNoRotate(boundsTL, false),\n sizeC = viewport.deltaPixelsFromPointsNoRotate(boundsSize, true),\n sizeT = viewport.deltaPixelsFromPointsNoRotate(boundsSize, false),\n tileCenter = positionT.plus( sizeT.divide( 2 ) ),\n tileSquaredDistance = viewportCenter.squaredDistanceTo( tileCenter );\n\n if ( !overlap ) {\n sizeC = sizeC.plus( new $.Point( 1, 1 ) );\n }\n\n if (tile.isRightMost && tiledImage.wrapHorizontal) {\n sizeC.x += 0.75; // Otherwise Firefox and Safari show seams\n }\n\n if (tile.isBottomMost && tiledImage.wrapVertical) {\n sizeC.y += 0.75; // Otherwise Firefox and Safari show seams\n }\n\n tile.position = positionC;\n tile.size = sizeC;\n tile.squaredDistance = tileSquaredDistance;\n tile.visibility = levelVisibility;\n}\n\n/**\n * @private\n * @inner\n * Updates the opacity of a tile according to the time it has been on screen\n * to perform a fade-in.\n * Updates coverage once a tile is fully opaque.\n * Returns whether the fade-in has completed.\n *\n * @param {OpenSeadragon.TiledImage} tiledImage\n * @param {OpenSeadragon.Tile} tile\n * @param {Number} x\n * @param {Number} y\n * @param {Number} level\n * @param {Number} levelOpacity\n * @param {Number} currentTime\n * @returns {Boolean}\n */\nfunction blendTile( tiledImage, tile, x, y, level, levelOpacity, currentTime ){\n var blendTimeMillis = 1000 * tiledImage.blendTime,\n deltaTime,\n opacity;\n\n if ( !tile.blendStart ) {\n tile.blendStart = currentTime;\n }\n\n deltaTime = currentTime - tile.blendStart;\n opacity = blendTimeMillis ? Math.min( 1, deltaTime / ( blendTimeMillis ) ) : 1;\n\n if ( tiledImage.alwaysBlend ) {\n opacity *= levelOpacity;\n }\n\n tile.opacity = opacity;\n\n tiledImage.lastDrawn.push( tile );\n\n if ( opacity == 1 ) {\n setCoverage( tiledImage.coverage, level, x, y, true );\n tiledImage._hasOpaqueTile = true;\n } else if ( deltaTime < blendTimeMillis ) {\n return true;\n }\n\n return false;\n}\n\n/**\n * @private\n * @inner\n * Returns true if the given tile provides coverage to lower-level tiles of\n * lower resolution representing the same content. If neither x nor y is\n * given, returns true if the entire visible level provides coverage.\n *\n * Note that out-of-bounds tiles provide coverage in this sense, since\n * there's no content that they would need to cover. Tiles at non-existent\n * levels that are within the image bounds, however, do not.\n *\n * @param {Object} coverage - A '3d' dictionary [level][x][y] --> Boolean.\n * @param {Number} level - The resolution level of the tile.\n * @param {Number} x - The X position of the tile.\n * @param {Number} y - The Y position of the tile.\n * @returns {Boolean}\n */\nfunction providesCoverage( coverage, level, x, y ) {\n var rows,\n cols,\n i, j;\n\n if ( !coverage[ level ] ) {\n return false;\n }\n\n if ( x === undefined || y === undefined ) {\n rows = coverage[ level ];\n for ( i in rows ) {\n if ( rows.hasOwnProperty( i ) ) {\n cols = rows[ i ];\n for ( j in cols ) {\n if ( cols.hasOwnProperty( j ) && !cols[ j ] ) {\n return false;\n }\n }\n }\n }\n\n return true;\n }\n\n return (\n coverage[ level ][ x] === undefined ||\n coverage[ level ][ x ][ y ] === undefined ||\n coverage[ level ][ x ][ y ] === true\n );\n}\n\n/**\n * @private\n * @inner\n * Returns true if the given tile is completely covered by higher-level\n * tiles of higher resolution representing the same content. If neither x\n * nor y is given, returns true if the entire visible level is covered.\n *\n * @param {Object} coverage - A '3d' dictionary [level][x][y] --> Boolean.\n * @param {Number} level - The resolution level of the tile.\n * @param {Number} x - The X position of the tile.\n * @param {Number} y - The Y position of the tile.\n * @returns {Boolean}\n */\nfunction isCovered( coverage, level, x, y ) {\n if ( x === undefined || y === undefined ) {\n return providesCoverage( coverage, level + 1 );\n } else {\n return (\n providesCoverage( coverage, level + 1, 2 * x, 2 * y ) &&\n providesCoverage( coverage, level + 1, 2 * x, 2 * y + 1 ) &&\n providesCoverage( coverage, level + 1, 2 * x + 1, 2 * y ) &&\n providesCoverage( coverage, level + 1, 2 * x + 1, 2 * y + 1 )\n );\n }\n}\n\n/**\n * @private\n * @inner\n * Sets whether the given tile provides coverage or not.\n *\n * @param {Object} coverage - A '3d' dictionary [level][x][y] --> Boolean.\n * @param {Number} level - The resolution level of the tile.\n * @param {Number} x - The X position of the tile.\n * @param {Number} y - The Y position of the tile.\n * @param {Boolean} covers - Whether the tile provides coverage.\n */\nfunction setCoverage( coverage, level, x, y, covers ) {\n if ( !coverage[ level ] ) {\n $.console.warn(\n \"Setting coverage for a tile before its level's coverage has been reset: %s\",\n level\n );\n return;\n }\n\n if ( !coverage[ level ][ x ] ) {\n coverage[ level ][ x ] = {};\n }\n\n coverage[ level ][ x ][ y ] = covers;\n}\n\n/**\n * @private\n * @inner\n * Resets coverage information for the given level. This should be called\n * after every draw routine. Note that at the beginning of the next draw\n * routine, coverage for every visible tile should be explicitly set.\n *\n * @param {Object} coverage - A '3d' dictionary [level][x][y] --> Boolean.\n * @param {Number} level - The resolution level of tiles to completely reset.\n */\nfunction resetCoverage( coverage, level ) {\n coverage[ level ] = {};\n}\n\n/**\n * @private\n * @inner\n * Determines whether the 'last best' tile for the area is better than the\n * tile in question.\n *\n * @param {OpenSeadragon.Tile} previousBest\n * @param {OpenSeadragon.Tile} tile\n * @returns {OpenSeadragon.Tile} The new best tile.\n */\nfunction compareTiles( previousBest, tile ) {\n if ( !previousBest ) {\n return tile;\n }\n\n if ( tile.visibility > previousBest.visibility ) {\n return tile;\n } else if ( tile.visibility == previousBest.visibility ) {\n if ( tile.squaredDistance < previousBest.squaredDistance ) {\n return tile;\n }\n }\n\n return previousBest;\n}\n\n/**\n * @private\n * @inner\n * Draws a TiledImage.\n * @param {OpenSeadragon.TiledImage} tiledImage\n * @param {OpenSeadragon.Tile[]} lastDrawn - An unordered list of Tiles drawn last frame.\n */\nfunction drawTiles( tiledImage, lastDrawn ) {\n if (tiledImage.opacity === 0 || (lastDrawn.length === 0 && !tiledImage.placeholderFillStyle)) {\n return;\n }\n\n var tile = lastDrawn[0];\n var useSketch;\n\n if (tile) {\n useSketch = tiledImage.opacity < 1 ||\n (tiledImage.compositeOperation &&\n tiledImage.compositeOperation !== 'source-over') ||\n (!tiledImage._isBottomItem() && tile._hasTransparencyChannel());\n }\n\n var sketchScale;\n var sketchTranslate;\n\n var zoom = tiledImage.viewport.getZoom(true);\n var imageZoom = tiledImage.viewportToImageZoom(zoom);\n\n if (lastDrawn.length > 1 &&\n imageZoom > tiledImage.smoothTileEdgesMinZoom &&\n !tiledImage.iOSDevice &&\n tiledImage.getRotation(true) % 360 === 0 && // TODO: support tile edge smoothing with tiled image rotation.\n $.supportsCanvas) {\n // When zoomed in a lot (>100%) the tile edges are visible.\n // So we have to composite them at ~100% and scale them up together.\n // Note: Disabled on iOS devices per default as it causes a native crash\n useSketch = true;\n sketchScale = tile.getScaleForEdgeSmoothing();\n sketchTranslate = tile.getTranslationForEdgeSmoothing(sketchScale,\n tiledImage._drawer.getCanvasSize(false),\n tiledImage._drawer.getCanvasSize(true));\n }\n\n var bounds;\n if (useSketch) {\n if (!sketchScale) {\n // Except when edge smoothing, we only clean the part of the\n // sketch canvas we are going to use for performance reasons.\n bounds = tiledImage.viewport.viewportToViewerElementRectangle(\n tiledImage.getClippedBounds(true))\n .getIntegerBoundingBox()\n .times($.pixelDensityRatio);\n }\n tiledImage._drawer._clear(true, bounds);\n }\n\n // When scaling, we must rotate only when blending the sketch canvas to\n // avoid interpolation\n if (!sketchScale) {\n if (tiledImage.viewport.degrees !== 0) {\n tiledImage._drawer._offsetForRotation({\n degrees: tiledImage.viewport.degrees,\n useSketch: useSketch\n });\n }\n if (tiledImage.getRotation(true) % 360 !== 0) {\n tiledImage._drawer._offsetForRotation({\n degrees: tiledImage.getRotation(true),\n point: tiledImage.viewport.pixelFromPointNoRotate(\n tiledImage._getRotationPoint(true), true),\n useSketch: useSketch\n });\n }\n }\n\n var usedClip = false;\n if ( tiledImage._clip ) {\n tiledImage._drawer.saveContext(useSketch);\n\n var box = tiledImage.imageToViewportRectangle(tiledImage._clip, true);\n box = box.rotate(-tiledImage.getRotation(true), tiledImage._getRotationPoint(true));\n var clipRect = tiledImage._drawer.viewportToDrawerRectangle(box);\n if (sketchScale) {\n clipRect = clipRect.times(sketchScale);\n }\n if (sketchTranslate) {\n clipRect = clipRect.translate(sketchTranslate);\n }\n tiledImage._drawer.setClip(clipRect, useSketch);\n\n usedClip = true;\n }\n\n if ( tiledImage.placeholderFillStyle && tiledImage._hasOpaqueTile === false ) {\n var placeholderRect = tiledImage._drawer.viewportToDrawerRectangle(tiledImage.getBounds(true));\n if (sketchScale) {\n placeholderRect = placeholderRect.times(sketchScale);\n }\n if (sketchTranslate) {\n placeholderRect = placeholderRect.translate(sketchTranslate);\n }\n\n var fillStyle = null;\n if ( typeof tiledImage.placeholderFillStyle === \"function\" ) {\n fillStyle = tiledImage.placeholderFillStyle(tiledImage, tiledImage._drawer.context);\n }\n else {\n fillStyle = tiledImage.placeholderFillStyle;\n }\n\n tiledImage._drawer.drawRectangle(placeholderRect, fillStyle, useSketch);\n }\n\n for (var i = lastDrawn.length - 1; i >= 0; i--) {\n tile = lastDrawn[ i ];\n tiledImage._drawer.drawTile( tile, tiledImage._drawingHandler, useSketch, sketchScale, sketchTranslate );\n tile.beingDrawn = true;\n\n if( tiledImage.viewer ){\n /**\n * - Needs documentation -\n *\n * @event tile-drawn\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.\n * @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.\n * @property {OpenSeadragon.Tile} tile\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n tiledImage.viewer.raiseEvent( 'tile-drawn', {\n tiledImage: tiledImage,\n tile: tile\n });\n }\n }\n\n if ( usedClip ) {\n tiledImage._drawer.restoreContext( useSketch );\n }\n\n if (!sketchScale) {\n if (tiledImage.getRotation(true) % 360 !== 0) {\n tiledImage._drawer._restoreRotationChanges(useSketch);\n }\n if (tiledImage.viewport.degrees !== 0) {\n tiledImage._drawer._restoreRotationChanges(useSketch);\n }\n }\n\n if (useSketch) {\n if (sketchScale) {\n if (tiledImage.viewport.degrees !== 0) {\n tiledImage._drawer._offsetForRotation({\n degrees: tiledImage.viewport.degrees,\n useSketch: false\n });\n }\n if (tiledImage.getRotation(true) % 360 !== 0) {\n tiledImage._drawer._offsetForRotation({\n degrees: tiledImage.getRotation(true),\n point: tiledImage.viewport.pixelFromPointNoRotate(\n tiledImage._getRotationPoint(true), true),\n useSketch: false\n });\n }\n }\n tiledImage._drawer.blendSketch({\n opacity: tiledImage.opacity,\n scale: sketchScale,\n translate: sketchTranslate,\n compositeOperation: tiledImage.compositeOperation,\n bounds: bounds\n });\n if (sketchScale) {\n if (tiledImage.getRotation(true) % 360 !== 0) {\n tiledImage._drawer._restoreRotationChanges(false);\n }\n if (tiledImage.viewport.degrees !== 0) {\n tiledImage._drawer._restoreRotationChanges(false);\n }\n }\n }\n drawDebugInfo( tiledImage, lastDrawn );\n}\n\n/**\n * @private\n * @inner\n * Draws special debug information for a TiledImage if in debug mode.\n * @param {OpenSeadragon.TiledImage} tiledImage\n * @param {OpenSeadragon.Tile[]} lastDrawn - An unordered list of Tiles drawn last frame.\n */\nfunction drawDebugInfo( tiledImage, lastDrawn ) {\n if( tiledImage.debugMode ) {\n for ( var i = lastDrawn.length - 1; i >= 0; i-- ) {\n var tile = lastDrawn[ i ];\n try {\n tiledImage._drawer.drawDebugInfo(\n tile, lastDrawn.length, i, tiledImage);\n } catch(e) {\n $.console.error(e);\n }\n }\n }\n}\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - TileCache\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n// private class\nvar TileRecord = function( options ) {\n $.console.assert( options, \"[TileCache.cacheTile] options is required\" );\n $.console.assert( options.tile, \"[TileCache.cacheTile] options.tile is required\" );\n $.console.assert( options.tiledImage, \"[TileCache.cacheTile] options.tiledImage is required\" );\n this.tile = options.tile;\n this.tiledImage = options.tiledImage;\n};\n\n// private class\nvar ImageRecord = function(options) {\n $.console.assert( options, \"[ImageRecord] options is required\" );\n $.console.assert( options.image, \"[ImageRecord] options.image is required\" );\n this._image = options.image;\n this._tiles = [];\n};\n\nImageRecord.prototype = {\n destroy: function() {\n this._image = null;\n this._renderedContext = null;\n this._tiles = null;\n },\n\n getImage: function() {\n return this._image;\n },\n\n getRenderedContext: function() {\n if (!this._renderedContext) {\n var canvas = document.createElement( 'canvas' );\n canvas.width = this._image.width;\n canvas.height = this._image.height;\n this._renderedContext = canvas.getContext('2d');\n this._renderedContext.drawImage( this._image, 0, 0 );\n //since we are caching the prerendered image on a canvas\n //allow the image to not be held in memory\n this._image = null;\n }\n return this._renderedContext;\n },\n\n setRenderedContext: function(renderedContext) {\n $.console.error(\"ImageRecord.setRenderedContext is deprecated. \" +\n \"The rendered context should be created by the ImageRecord \" +\n \"itself when calling ImageRecord.getRenderedContext.\");\n this._renderedContext = renderedContext;\n },\n\n addTile: function(tile) {\n $.console.assert(tile, '[ImageRecord.addTile] tile is required');\n this._tiles.push(tile);\n },\n\n removeTile: function(tile) {\n for (var i = 0; i < this._tiles.length; i++) {\n if (this._tiles[i] === tile) {\n this._tiles.splice(i, 1);\n return;\n }\n }\n\n $.console.warn('[ImageRecord.removeTile] trying to remove unknown tile', tile);\n },\n\n getTileCount: function() {\n return this._tiles.length;\n }\n};\n\n/**\n * @class TileCache\n * @memberof OpenSeadragon\n * @classdesc Stores all the tiles displayed in a {@link OpenSeadragon.Viewer}.\n * You generally won't have to interact with the TileCache directly.\n * @param {Object} options - Configuration for this TileCache.\n * @param {Number} [options.maxImageCacheCount] - See maxImageCacheCount in\n * {@link OpenSeadragon.Options} for details.\n */\n$.TileCache = function( options ) {\n options = options || {};\n\n this._maxImageCacheCount = options.maxImageCacheCount || $.DEFAULT_SETTINGS.maxImageCacheCount;\n this._tilesLoaded = [];\n this._imagesLoaded = [];\n this._imagesLoadedCount = 0;\n};\n\n/** @lends OpenSeadragon.TileCache.prototype */\n$.TileCache.prototype = {\n /**\n * @returns {Number} The total number of tiles that have been loaded by\n * this TileCache.\n */\n numTilesLoaded: function() {\n return this._tilesLoaded.length;\n },\n\n /**\n * Caches the specified tile, removing an old tile if necessary to stay under the\n * maxImageCacheCount specified on construction. Note that if multiple tiles reference\n * the same image, there may be more tiles than maxImageCacheCount; the goal is to keep\n * the number of images below that number. Note, as well, that even the number of images\n * may temporarily surpass that number, but should eventually come back down to the max specified.\n * @param {Object} options - Tile info.\n * @param {OpenSeadragon.Tile} options.tile - The tile to cache.\n * @param {String} options.tile.cacheKey - The unique key used to identify this tile in the cache.\n * @param {Image} options.image - The image of the tile to cache.\n * @param {OpenSeadragon.TiledImage} options.tiledImage - The TiledImage that owns that tile.\n * @param {Number} [options.cutoff=0] - If adding this tile goes over the cache max count, this\n * function will release an old tile. The cutoff option specifies a tile level at or below which\n * tiles will not be released.\n */\n cacheTile: function( options ) {\n $.console.assert( options, \"[TileCache.cacheTile] options is required\" );\n $.console.assert( options.tile, \"[TileCache.cacheTile] options.tile is required\" );\n $.console.assert( options.tile.cacheKey, \"[TileCache.cacheTile] options.tile.cacheKey is required\" );\n $.console.assert( options.tiledImage, \"[TileCache.cacheTile] options.tiledImage is required\" );\n\n var cutoff = options.cutoff || 0;\n var insertionIndex = this._tilesLoaded.length;\n\n var imageRecord = this._imagesLoaded[options.tile.cacheKey];\n if (!imageRecord) {\n $.console.assert( options.image, \"[TileCache.cacheTile] options.image is required to create an ImageRecord\" );\n imageRecord = this._imagesLoaded[options.tile.cacheKey] = new ImageRecord({\n image: options.image\n });\n\n this._imagesLoadedCount++;\n }\n\n imageRecord.addTile(options.tile);\n options.tile.cacheImageRecord = imageRecord;\n\n // Note that just because we're unloading a tile doesn't necessarily mean\n // we're unloading an image. With repeated calls it should sort itself out, though.\n if ( this._imagesLoadedCount > this._maxImageCacheCount ) {\n var worstTile = null;\n var worstTileIndex = -1;\n var worstTileRecord = null;\n var prevTile, worstTime, worstLevel, prevTime, prevLevel, prevTileRecord;\n\n for ( var i = this._tilesLoaded.length - 1; i >= 0; i-- ) {\n prevTileRecord = this._tilesLoaded[ i ];\n prevTile = prevTileRecord.tile;\n\n if ( prevTile.level <= cutoff || prevTile.beingDrawn ) {\n continue;\n } else if ( !worstTile ) {\n worstTile = prevTile;\n worstTileIndex = i;\n worstTileRecord = prevTileRecord;\n continue;\n }\n\n prevTime = prevTile.lastTouchTime;\n worstTime = worstTile.lastTouchTime;\n prevLevel = prevTile.level;\n worstLevel = worstTile.level;\n\n if ( prevTime < worstTime ||\n ( prevTime == worstTime && prevLevel > worstLevel ) ) {\n worstTile = prevTile;\n worstTileIndex = i;\n worstTileRecord = prevTileRecord;\n }\n }\n\n if ( worstTile && worstTileIndex >= 0 ) {\n this._unloadTile(worstTileRecord);\n insertionIndex = worstTileIndex;\n }\n }\n\n this._tilesLoaded[ insertionIndex ] = new TileRecord({\n tile: options.tile,\n tiledImage: options.tiledImage\n });\n },\n\n /**\n * Clears all tiles associated with the specified tiledImage.\n * @param {OpenSeadragon.TiledImage} tiledImage\n */\n clearTilesFor: function( tiledImage ) {\n $.console.assert(tiledImage, '[TileCache.clearTilesFor] tiledImage is required');\n var tileRecord;\n for ( var i = 0; i < this._tilesLoaded.length; ++i ) {\n tileRecord = this._tilesLoaded[ i ];\n if ( tileRecord.tiledImage === tiledImage ) {\n this._unloadTile(tileRecord);\n this._tilesLoaded.splice( i, 1 );\n i--;\n }\n }\n },\n\n // private\n getImageRecord: function(cacheKey) {\n $.console.assert(cacheKey, '[TileCache.getImageRecord] cacheKey is required');\n return this._imagesLoaded[cacheKey];\n },\n\n // private\n _unloadTile: function(tileRecord) {\n $.console.assert(tileRecord, '[TileCache._unloadTile] tileRecord is required');\n var tile = tileRecord.tile;\n var tiledImage = tileRecord.tiledImage;\n\n tile.unload();\n tile.cacheImageRecord = null;\n\n var imageRecord = this._imagesLoaded[tile.cacheKey];\n imageRecord.removeTile(tile);\n if (!imageRecord.getTileCount()) {\n imageRecord.destroy();\n delete this._imagesLoaded[tile.cacheKey];\n this._imagesLoadedCount--;\n }\n\n /**\n * Triggered when a tile has just been unloaded from memory.\n *\n * @event tile-unloaded\n * @memberof OpenSeadragon.Viewer\n * @type {object}\n * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image of the unloaded tile.\n * @property {OpenSeadragon.Tile} tile - The tile which has been unloaded.\n */\n tiledImage.viewer.raiseEvent(\"tile-unloaded\", {\n tile: tile,\n tiledImage: tiledImage\n });\n }\n};\n\n}( OpenSeadragon ));\n","/*\n * OpenSeadragon - World\n *\n * Copyright (C) 2009 CodePlex Foundation\n * Copyright (C) 2010-2013 OpenSeadragon contributors\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * - Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * - Neither the name of CodePlex Foundation nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function( $ ){\n\n/**\n * @class World\n * @memberof OpenSeadragon\n * @extends OpenSeadragon.EventSource\n * @classdesc Keeps track of all of the tiled images in the scene.\n * @param {Object} options - World options.\n * @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this World.\n **/\n$.World = function( options ) {\n var _this = this;\n\n $.console.assert( options.viewer, \"[World] options.viewer is required\" );\n\n $.EventSource.call( this );\n\n this.viewer = options.viewer;\n this._items = [];\n this._needsDraw = false;\n this._autoRefigureSizes = true;\n this._needsSizesFigured = false;\n this._delegatedFigureSizes = function(event) {\n if (_this._autoRefigureSizes) {\n _this._figureSizes();\n } else {\n _this._needsSizesFigured = true;\n }\n };\n\n this._figureSizes();\n};\n\n$.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.World.prototype */{\n /**\n * Add the specified item.\n * @param {OpenSeadragon.TiledImage} item - The item to add.\n * @param {Number} [options.index] - Index for the item. If not specified, goes at the top.\n * @fires OpenSeadragon.World.event:add-item\n * @fires OpenSeadragon.World.event:metrics-change\n */\n addItem: function( item, options ) {\n $.console.assert(item, \"[World.addItem] item is required\");\n $.console.assert(item instanceof $.TiledImage, \"[World.addItem] only TiledImages supported at this time\");\n\n options = options || {};\n if (options.index !== undefined) {\n var index = Math.max(0, Math.min(this._items.length, options.index));\n this._items.splice(index, 0, item);\n } else {\n this._items.push( item );\n }\n\n if (this._autoRefigureSizes) {\n this._figureSizes();\n } else {\n this._needsSizesFigured = true;\n }\n\n this._needsDraw = true;\n\n item.addHandler('bounds-change', this._delegatedFigureSizes);\n item.addHandler('clip-change', this._delegatedFigureSizes);\n\n /**\n * Raised when an item is added to the World.\n * @event add-item\n * @memberOf OpenSeadragon.World\n * @type {object}\n * @property {OpenSeadragon.Viewer} eventSource - A reference to the World which raised the event.\n * @property {OpenSeadragon.TiledImage} item - The item that has been added.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'add-item', {\n item: item\n } );\n },\n\n /**\n * Get the item at the specified index.\n * @param {Number} index - The item's index.\n * @returns {OpenSeadragon.TiledImage} The item at the specified index.\n */\n getItemAt: function( index ) {\n $.console.assert(index !== undefined, \"[World.getItemAt] index is required\");\n return this._items[ index ];\n },\n\n /**\n * Get the index of the given item or -1 if not present.\n * @param {OpenSeadragon.TiledImage} item - The item.\n * @returns {Number} The index of the item or -1 if not present.\n */\n getIndexOfItem: function( item ) {\n $.console.assert(item, \"[World.getIndexOfItem] item is required\");\n return $.indexOf( this._items, item );\n },\n\n /**\n * @returns {Number} The number of items used.\n */\n getItemCount: function() {\n return this._items.length;\n },\n\n /**\n * Change the index of a item so that it appears over or under others.\n * @param {OpenSeadragon.TiledImage} item - The item to move.\n * @param {Number} index - The new index.\n * @fires OpenSeadragon.World.event:item-index-change\n */\n setItemIndex: function( item, index ) {\n $.console.assert(item, \"[World.setItemIndex] item is required\");\n $.console.assert(index !== undefined, \"[World.setItemIndex] index is required\");\n\n var oldIndex = this.getIndexOfItem( item );\n\n if ( index >= this._items.length ) {\n throw new Error( \"Index bigger than number of layers.\" );\n }\n\n if ( index === oldIndex || oldIndex === -1 ) {\n return;\n }\n\n this._items.splice( oldIndex, 1 );\n this._items.splice( index, 0, item );\n this._needsDraw = true;\n\n /**\n * Raised when the order of the indexes has been changed.\n * @event item-index-change\n * @memberOf OpenSeadragon.World\n * @type {object}\n * @property {OpenSeadragon.World} eventSource - A reference to the World which raised the event.\n * @property {OpenSeadragon.TiledImage} item - The item whose index has\n * been changed\n * @property {Number} previousIndex - The previous index of the item\n * @property {Number} newIndex - The new index of the item\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'item-index-change', {\n item: item,\n previousIndex: oldIndex,\n newIndex: index\n } );\n },\n\n /**\n * Remove an item.\n * @param {OpenSeadragon.TiledImage} item - The item to remove.\n * @fires OpenSeadragon.World.event:remove-item\n * @fires OpenSeadragon.World.event:metrics-change\n */\n removeItem: function( item ) {\n $.console.assert(item, \"[World.removeItem] item is required\");\n\n var index = $.indexOf(this._items, item );\n if ( index === -1 ) {\n return;\n }\n\n item.removeHandler('bounds-change', this._delegatedFigureSizes);\n item.removeHandler('clip-change', this._delegatedFigureSizes);\n item.destroy();\n this._items.splice( index, 1 );\n this._figureSizes();\n this._needsDraw = true;\n this._raiseRemoveItem(item);\n },\n\n /**\n * Remove all items.\n * @fires OpenSeadragon.World.event:remove-item\n * @fires OpenSeadragon.World.event:metrics-change\n */\n removeAll: function() {\n // We need to make sure any pending images are canceled so the world items don't get messed up\n this.viewer._cancelPendingImages();\n var item;\n var i;\n for (i = 0; i < this._items.length; i++) {\n item = this._items[i];\n item.removeHandler('bounds-change', this._delegatedFigureSizes);\n item.removeHandler('clip-change', this._delegatedFigureSizes);\n item.destroy();\n }\n\n var removedItems = this._items;\n this._items = [];\n this._figureSizes();\n this._needsDraw = true;\n\n for (i = 0; i < removedItems.length; i++) {\n item = removedItems[i];\n this._raiseRemoveItem(item);\n }\n },\n\n /**\n * Clears all tiles and triggers updates for all items.\n */\n resetItems: function() {\n for ( var i = 0; i < this._items.length; i++ ) {\n this._items[i].reset();\n }\n },\n\n /**\n * Updates (i.e. animates bounds of) all items.\n */\n update: function() {\n var animated = false;\n for ( var i = 0; i < this._items.length; i++ ) {\n animated = this._items[i].update() || animated;\n }\n\n return animated;\n },\n\n /**\n * Draws all items.\n */\n draw: function() {\n for ( var i = 0; i < this._items.length; i++ ) {\n this._items[i].draw();\n }\n\n this._needsDraw = false;\n },\n\n /**\n * @returns {Boolean} true if any items need updating.\n */\n needsDraw: function() {\n for ( var i = 0; i < this._items.length; i++ ) {\n if ( this._items[i].needsDraw() ) {\n return true;\n }\n }\n return this._needsDraw;\n },\n\n /**\n * @returns {OpenSeadragon.Rect} The smallest rectangle that encloses all items, in viewport coordinates.\n */\n getHomeBounds: function() {\n return this._homeBounds.clone();\n },\n\n /**\n * To facilitate zoom constraints, we keep track of the pixel density of the\n * densest item in the World (i.e. the item whose content size to viewport size\n * ratio is the highest) and save it as this \"content factor\".\n * @returns {Number} the number of content units per viewport unit.\n */\n getContentFactor: function() {\n return this._contentFactor;\n },\n\n /**\n * As a performance optimization, setting this flag to false allows the bounds-change event handler\n * on tiledImages to skip calculations on the world bounds. If a lot of images are going to be positioned in\n * rapid succession, this is a good idea. When finished, setAutoRefigureSizes should be called with true\n * or the system may behave oddly.\n * @param {Boolean} [value] The value to which to set the flag.\n */\n setAutoRefigureSizes: function(value) {\n this._autoRefigureSizes = value;\n if (value & this._needsSizesFigured) {\n this._figureSizes();\n this._needsSizesFigured = false;\n }\n },\n\n /**\n * Arranges all of the TiledImages with the specified settings.\n * @param {Object} options - Specifies how to arrange.\n * @param {Boolean} [options.immediately=false] - Whether to animate to the new arrangement.\n * @param {String} [options.layout] - See collectionLayout in {@link OpenSeadragon.Options}.\n * @param {Number} [options.rows] - See collectionRows in {@link OpenSeadragon.Options}.\n * @param {Number} [options.columns] - See collectionColumns in {@link OpenSeadragon.Options}.\n * @param {Number} [options.tileSize] - See collectionTileSize in {@link OpenSeadragon.Options}.\n * @param {Number} [options.tileMargin] - See collectionTileMargin in {@link OpenSeadragon.Options}.\n * @fires OpenSeadragon.World.event:metrics-change\n */\n arrange: function(options) {\n options = options || {};\n var immediately = options.immediately || false;\n var layout = options.layout || $.DEFAULT_SETTINGS.collectionLayout;\n var rows = options.rows || $.DEFAULT_SETTINGS.collectionRows;\n var columns = options.columns || $.DEFAULT_SETTINGS.collectionColumns;\n var tileSize = options.tileSize || $.DEFAULT_SETTINGS.collectionTileSize;\n var tileMargin = options.tileMargin || $.DEFAULT_SETTINGS.collectionTileMargin;\n var increment = tileSize + tileMargin;\n var wrap;\n if (!options.rows && columns) {\n wrap = columns;\n } else {\n wrap = Math.ceil(this._items.length / rows);\n }\n var x = 0;\n var y = 0;\n var item, box, width, height, position;\n\n this.setAutoRefigureSizes(false);\n for (var i = 0; i < this._items.length; i++) {\n if (i && (i % wrap) === 0) {\n if (layout === 'horizontal') {\n y += increment;\n x = 0;\n } else {\n x += increment;\n y = 0;\n }\n }\n\n item = this._items[i];\n box = item.getBounds();\n if (box.width > box.height) {\n width = tileSize;\n } else {\n width = tileSize * (box.width / box.height);\n }\n\n height = width * (box.height / box.width);\n position = new $.Point(x + ((tileSize - width) / 2),\n y + ((tileSize - height) / 2));\n\n item.setPosition(position, immediately);\n item.setWidth(width, immediately);\n\n if (layout === 'horizontal') {\n x += increment;\n } else {\n y += increment;\n }\n }\n this.setAutoRefigureSizes(true);\n },\n\n // private\n _figureSizes: function() {\n var oldHomeBounds = this._homeBounds ? this._homeBounds.clone() : null;\n var oldContentSize = this._contentSize ? this._contentSize.clone() : null;\n var oldContentFactor = this._contentFactor || 0;\n\n if (!this._items.length) {\n this._homeBounds = new $.Rect(0, 0, 1, 1);\n this._contentSize = new $.Point(1, 1);\n this._contentFactor = 1;\n } else {\n var item = this._items[0];\n var bounds = item.getBounds();\n this._contentFactor = item.getContentSize().x / bounds.width;\n var clippedBounds = item.getClippedBounds().getBoundingBox();\n var left = clippedBounds.x;\n var top = clippedBounds.y;\n var right = clippedBounds.x + clippedBounds.width;\n var bottom = clippedBounds.y + clippedBounds.height;\n for (var i = 1; i < this._items.length; i++) {\n item = this._items[i];\n bounds = item.getBounds();\n this._contentFactor = Math.max(this._contentFactor,\n item.getContentSize().x / bounds.width);\n clippedBounds = item.getClippedBounds().getBoundingBox();\n left = Math.min(left, clippedBounds.x);\n top = Math.min(top, clippedBounds.y);\n right = Math.max(right, clippedBounds.x + clippedBounds.width);\n bottom = Math.max(bottom, clippedBounds.y + clippedBounds.height);\n }\n\n this._homeBounds = new $.Rect(left, top, right - left, bottom - top);\n this._contentSize = new $.Point(\n this._homeBounds.width * this._contentFactor,\n this._homeBounds.height * this._contentFactor);\n }\n\n if (this._contentFactor !== oldContentFactor ||\n !this._homeBounds.equals(oldHomeBounds) ||\n !this._contentSize.equals(oldContentSize)) {\n /**\n * Raised when the home bounds or content factor change.\n * @event metrics-change\n * @memberOf OpenSeadragon.World\n * @type {object}\n * @property {OpenSeadragon.World} eventSource - A reference to the World which raised the event.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent('metrics-change', {});\n }\n },\n\n // private\n _raiseRemoveItem: function(item) {\n /**\n * Raised when an item is removed.\n * @event remove-item\n * @memberOf OpenSeadragon.World\n * @type {object}\n * @property {OpenSeadragon.World} eventSource - A reference to the World which raised the event.\n * @property {OpenSeadragon.TiledImage} item - The item's underlying item.\n * @property {?Object} userData - Arbitrary subscriber-defined object.\n */\n this.raiseEvent( 'remove-item', { item: item } );\n }\n});\n\n}( OpenSeadragon ));\n"]} \ No newline at end of file diff --git a/js/openseadragon/openseadragon-imaginghelper.min.BAK.js b/js/openseadragon/openseadragon-imaginghelper.min.BAK.js new file mode 100644 index 000000000..9968d1a50 --- /dev/null +++ b/js/openseadragon/openseadragon-imaginghelper.min.BAK.js @@ -0,0 +1,5 @@ +//! OpenSeadragonImagingHelper 1.1.0 +//! Build date: 2014-01-13 +//! Git commit: v1.0.0-17-g2322896 +//! https://github.com/msalsbery/OpenSeadragonImagingHelper +!function(a,b){function c(){this._haveImage=!0,this.imgWidth=this._viewer.viewport.contentSize.x,this.imgHeight=this._viewer.viewport.contentSize.y,this.imgAspectRatio=this.imgWidth/this.imgHeight,this._trackZoomPan()}function d(){this._haveImage=!1,this.imgWidth=0,this.imgHeight=0,this.imgAspectRatio=0}function e(){this._trackZoomPan()}function f(){this._trackZoomPan()}function g(){this._viewer&&this._viewer.autoResize&&this._trackZoomPan()}function h(){this._trackZoomPan()}function i(){this._trackZoomPan()}a.Viewer.prototype.activateImagingHelper=function(a){return this.imagingHelper||(a=a||{},a.viewer=this,this.imagingHelper=new b.ImagingHelper(a)),this.imagingHelper},b.ImagingHelper=function(b){if(b=b||{},!b.viewer)throw new Error("A viewer must be specified.");if(b.viewer.imagingHelper)throw new Error("Viewer already has an ImagingHelper.");this._viewer=b.viewer,a.EventSource.call(this),this._viewer.imagingHelper=this,this.options=b,this.imgWidth=0,this.imgHeight=0,this.imgAspectRatio=0,this._zoomFactor=1,this._minZoom=.001,this._maxZoom=10,this._zoomStepPercent=30,this._haveImage=!1,this._viewerSize=null,this._viewportWidth=0,this._viewportHeight=0,this._viewportOrigin=new OpenSeadragon.Point(0,0),this._viewportCenter=new OpenSeadragon.Point(0,0),b.onImageViewChanged&&this.addHandler("image-view-changed",b.onImageViewChanged),this._viewer.addHandler("open",a.delegate(this,c)),this._viewer.addHandler("close",a.delegate(this,d)),this._viewer.addHandler("animation",a.delegate(this,e)),this._viewer.addHandler("animation-finish",a.delegate(this,f)),this._viewer.addHandler("resize",a.delegate(this,g)),this._viewer.addHandler("full-page",a.delegate(this,h)),this._viewer.addHandler("full-screen",a.delegate(this,i))},b.ImagingHelper.version={versionStr:"1.1.0",major:1,minor:1,revision:0},a.extend(b.ImagingHelper.prototype,a.EventSource.prototype,{_raiseImageViewChanged:function(){this.raiseEvent("image-view-changed",{viewportWidth:this._viewportWidth,viewportHeight:this._viewportHeight,viewportOrigin:this._viewportOrigin,viewportCenter:this._viewportCenter,zoomFactor:this._zoomFactor})},_trackZoomPan:function(){var a=this._viewer.viewport.getBounds(!0);this._viewportOrigin.x=a.x,this._viewportOrigin.y=a.y*this.imgAspectRatio,this._viewportWidth=a.width,this._viewportHeight=a.height*this.imgAspectRatio,this._viewportCenter.x=this._viewportOrigin.x+this._viewportWidth/2,this._viewportCenter.y=this._viewportOrigin.y+this._viewportHeight/2,this._zoomFactor=this.getViewerContainerSize().x/(this._viewportWidth*this.imgWidth),this._raiseImageViewChanged()},getViewerContainerSize:function(){var b=this._viewer.container;return new a.Point(b.clientWidth,b.clientHeight)},notifyResize:function(){var a,b,c;this._haveImage&&(a=this.getViewerContainerSize(),a.equals(this._viewerSize)||(this._viewerSize=a,b=new OpenSeadragon.Point(this._viewportCenter.x,this._viewportCenter.y/this.imgAspectRatio),c=this._zoomFactor,this._viewer.viewport.resize(a,!1),this._viewer.viewport.zoomTo(c*this.imgWidth/a.x,null,!0),this._viewer.viewport.panTo(b,!0),this._raiseImageViewChanged()))},getMinZoom:function(){return this._minZoom},setMinZoom:function(a){this._minZoom=a,this._viewer.minZoomLevel=a*this.imgWidth/this.getViewerContainerSize().x},getMaxZoom:function(){return this._maxZoom},setMaxZoom:function(a){this._maxZoom=a,this._viewer.maxZoomLevel=a*this.imgWidth/this.getViewerContainerSize().x},getZoomStepPercent:function(){return this._zoomStepPercent},setZoomStepPercent:function(a){this._zoomStepPercent=a},setView:function(a,b,c,d){this._haveImage&&((this._viewportWidth!=a||this._viewportHeight!=b)&&this._viewer.viewport.zoomTo(1/a,null,d),(this._viewportCenter.x!=c.x||this._viewportCenter.y!=c.y)&&this._viewer.viewport.panTo(new OpenSeadragon.Point(c.x,c.y/this.imgAspectRatio),d))},getZoomFactor:function(){return this._zoomFactor},setZoomFactor:function(a,b){this._haveImage&&a!=this._zoomFactor&&a>0&&this._viewer.viewport.zoomTo(a*this.imgWidth/this.getViewerContainerSize().x,new OpenSeadragon.Point(this._viewportCenter.x,this._viewportCenter.y/this.imgAspectRatio),b)},zoomIn:function(a){var b=this._zoomFactor;b*=1+this._zoomStepPercent/100,b>this._maxZoom&&(b=this._maxZoom),this.setZoomFactor(b,a)},zoomOut:function(a){var b=this._zoomFactor;b*=1-this._zoomStepPercent/100,b0&&this._viewer.viewport.zoomTo(a*this.imgWidth/this.getViewerContainerSize().x,new OpenSeadragon.Point(b.x,b.y/this.imgAspectRatio),c)},zoomInAboutLogicalPoint:function(a,b){var c=this._zoomFactor;c*=1+this._zoomStepPercent/100,c>this._maxZoom&&(c=this._maxZoom),this.zoomAboutLogicalPoint(c,a,b)},zoomOutAboutLogicalPoint:function(a,b){var c=this._zoomFactor;c*=1-this._zoomStepPercent/100,c0?a/this.imgWidth:0},dataToLogicalY:function(a){return this._haveImage&&this.imgHeight>0?a/this.imgHeight:0},physicalToDataX:function(a){return this._haveImage&&this.getViewerContainerSize().x>0?(this._viewportOrigin.x+a/this.getViewerContainerSize().x*this._viewportWidth)*this.imgWidth:0},physicalToDataY:function(a){return this._haveImage&&this.getViewerContainerSize().y>0?(this._viewportOrigin.y+a/this.getViewerContainerSize().y*this._viewportHeight)*this.imgHeight:0},dataToPhysicalX:function(a){return this._haveImage&&this.imgWidth>0?(a/this.imgWidth-this._viewportOrigin.x)/this._viewportWidth*this.getViewerContainerSize().x:0},dataToPhysicalY:function(a){return this._haveImage&&this.imgHeight>0?(a/this.imgHeight-this._viewportOrigin.y)/this._viewportHeight*this.getViewerContainerSize().y:0}})}(OpenSeadragon,window.OpenSeadragonImaging=window.OpenSeadragonImaging||{}); \ No newline at end of file diff --git a/js/openseadragon/openseadragon-imaginghelper.min.js b/js/openseadragon/openseadragon-imaginghelper.min.js index 9968d1a50..44c7f565f 100644 --- a/js/openseadragon/openseadragon-imaginghelper.min.js +++ b/js/openseadragon/openseadragon-imaginghelper.min.js @@ -1,5 +1,5 @@ -//! OpenSeadragonImagingHelper 1.1.0 -//! Build date: 2014-01-13 -//! Git commit: v1.0.0-17-g2322896 -//! https://github.com/msalsbery/OpenSeadragonImagingHelper -!function(a,b){function c(){this._haveImage=!0,this.imgWidth=this._viewer.viewport.contentSize.x,this.imgHeight=this._viewer.viewport.contentSize.y,this.imgAspectRatio=this.imgWidth/this.imgHeight,this._trackZoomPan()}function d(){this._haveImage=!1,this.imgWidth=0,this.imgHeight=0,this.imgAspectRatio=0}function e(){this._trackZoomPan()}function f(){this._trackZoomPan()}function g(){this._viewer&&this._viewer.autoResize&&this._trackZoomPan()}function h(){this._trackZoomPan()}function i(){this._trackZoomPan()}a.Viewer.prototype.activateImagingHelper=function(a){return this.imagingHelper||(a=a||{},a.viewer=this,this.imagingHelper=new b.ImagingHelper(a)),this.imagingHelper},b.ImagingHelper=function(b){if(b=b||{},!b.viewer)throw new Error("A viewer must be specified.");if(b.viewer.imagingHelper)throw new Error("Viewer already has an ImagingHelper.");this._viewer=b.viewer,a.EventSource.call(this),this._viewer.imagingHelper=this,this.options=b,this.imgWidth=0,this.imgHeight=0,this.imgAspectRatio=0,this._zoomFactor=1,this._minZoom=.001,this._maxZoom=10,this._zoomStepPercent=30,this._haveImage=!1,this._viewerSize=null,this._viewportWidth=0,this._viewportHeight=0,this._viewportOrigin=new OpenSeadragon.Point(0,0),this._viewportCenter=new OpenSeadragon.Point(0,0),b.onImageViewChanged&&this.addHandler("image-view-changed",b.onImageViewChanged),this._viewer.addHandler("open",a.delegate(this,c)),this._viewer.addHandler("close",a.delegate(this,d)),this._viewer.addHandler("animation",a.delegate(this,e)),this._viewer.addHandler("animation-finish",a.delegate(this,f)),this._viewer.addHandler("resize",a.delegate(this,g)),this._viewer.addHandler("full-page",a.delegate(this,h)),this._viewer.addHandler("full-screen",a.delegate(this,i))},b.ImagingHelper.version={versionStr:"1.1.0",major:1,minor:1,revision:0},a.extend(b.ImagingHelper.prototype,a.EventSource.prototype,{_raiseImageViewChanged:function(){this.raiseEvent("image-view-changed",{viewportWidth:this._viewportWidth,viewportHeight:this._viewportHeight,viewportOrigin:this._viewportOrigin,viewportCenter:this._viewportCenter,zoomFactor:this._zoomFactor})},_trackZoomPan:function(){var a=this._viewer.viewport.getBounds(!0);this._viewportOrigin.x=a.x,this._viewportOrigin.y=a.y*this.imgAspectRatio,this._viewportWidth=a.width,this._viewportHeight=a.height*this.imgAspectRatio,this._viewportCenter.x=this._viewportOrigin.x+this._viewportWidth/2,this._viewportCenter.y=this._viewportOrigin.y+this._viewportHeight/2,this._zoomFactor=this.getViewerContainerSize().x/(this._viewportWidth*this.imgWidth),this._raiseImageViewChanged()},getViewerContainerSize:function(){var b=this._viewer.container;return new a.Point(b.clientWidth,b.clientHeight)},notifyResize:function(){var a,b,c;this._haveImage&&(a=this.getViewerContainerSize(),a.equals(this._viewerSize)||(this._viewerSize=a,b=new OpenSeadragon.Point(this._viewportCenter.x,this._viewportCenter.y/this.imgAspectRatio),c=this._zoomFactor,this._viewer.viewport.resize(a,!1),this._viewer.viewport.zoomTo(c*this.imgWidth/a.x,null,!0),this._viewer.viewport.panTo(b,!0),this._raiseImageViewChanged()))},getMinZoom:function(){return this._minZoom},setMinZoom:function(a){this._minZoom=a,this._viewer.minZoomLevel=a*this.imgWidth/this.getViewerContainerSize().x},getMaxZoom:function(){return this._maxZoom},setMaxZoom:function(a){this._maxZoom=a,this._viewer.maxZoomLevel=a*this.imgWidth/this.getViewerContainerSize().x},getZoomStepPercent:function(){return this._zoomStepPercent},setZoomStepPercent:function(a){this._zoomStepPercent=a},setView:function(a,b,c,d){this._haveImage&&((this._viewportWidth!=a||this._viewportHeight!=b)&&this._viewer.viewport.zoomTo(1/a,null,d),(this._viewportCenter.x!=c.x||this._viewportCenter.y!=c.y)&&this._viewer.viewport.panTo(new OpenSeadragon.Point(c.x,c.y/this.imgAspectRatio),d))},getZoomFactor:function(){return this._zoomFactor},setZoomFactor:function(a,b){this._haveImage&&a!=this._zoomFactor&&a>0&&this._viewer.viewport.zoomTo(a*this.imgWidth/this.getViewerContainerSize().x,new OpenSeadragon.Point(this._viewportCenter.x,this._viewportCenter.y/this.imgAspectRatio),b)},zoomIn:function(a){var b=this._zoomFactor;b*=1+this._zoomStepPercent/100,b>this._maxZoom&&(b=this._maxZoom),this.setZoomFactor(b,a)},zoomOut:function(a){var b=this._zoomFactor;b*=1-this._zoomStepPercent/100,b0&&this._viewer.viewport.zoomTo(a*this.imgWidth/this.getViewerContainerSize().x,new OpenSeadragon.Point(b.x,b.y/this.imgAspectRatio),c)},zoomInAboutLogicalPoint:function(a,b){var c=this._zoomFactor;c*=1+this._zoomStepPercent/100,c>this._maxZoom&&(c=this._maxZoom),this.zoomAboutLogicalPoint(c,a,b)},zoomOutAboutLogicalPoint:function(a,b){var c=this._zoomFactor;c*=1-this._zoomStepPercent/100,c0?a/this.imgWidth:0},dataToLogicalY:function(a){return this._haveImage&&this.imgHeight>0?a/this.imgHeight:0},physicalToDataX:function(a){return this._haveImage&&this.getViewerContainerSize().x>0?(this._viewportOrigin.x+a/this.getViewerContainerSize().x*this._viewportWidth)*this.imgWidth:0},physicalToDataY:function(a){return this._haveImage&&this.getViewerContainerSize().y>0?(this._viewportOrigin.y+a/this.getViewerContainerSize().y*this._viewportHeight)*this.imgHeight:0},dataToPhysicalX:function(a){return this._haveImage&&this.imgWidth>0?(a/this.imgWidth-this._viewportOrigin.x)/this._viewportWidth*this.getViewerContainerSize().x:0},dataToPhysicalY:function(a){return this._haveImage&&this.imgHeight>0?(a/this.imgHeight-this._viewportOrigin.y)/this._viewportHeight*this.getViewerContainerSize().y:0}})}(OpenSeadragon,window.OpenSeadragonImaging=window.OpenSeadragonImaging||{}); \ No newline at end of file +//! OpenSeadragonImagingHelper 1.2.0 +//! Build date: 2017-11-07 +//! Git commit: v1.2.0-6-ge1a5465 +//! https://github.com/msalsbery/OpenSeadragonImagingHelper +!function(a,b,c){function d(){this._haveImage=!0;var a,b={};if(this._viewer.viewport.contentSize)a=this._viewer.viewport.contentSize;else{var c=this._viewer.world.getHomeBounds();b.x=c.width-c.x,b.y=c.height-c.y,a=this._viewer.world.getItemAt(0).viewportToImageCoordinates(b.x,b.y)}this.imgWidth=a.x,this.imgHeight=a.y,this.imgAspectRatio=this.imgWidth/this.imgHeight,this._trackZoomPan()}function e(){this._haveImage=!1,this.imgWidth=0,this.imgHeight=0,this.imgAspectRatio=0}function f(){this._trackZoomPan()}function g(){this._trackZoomPan()}function h(){this._viewer&&this._viewer.autoResize&&this._trackZoomPan()}function i(){this._trackZoomPan()}function j(){this._trackZoomPan()}a.Viewer.prototype.activateImagingHelper=function(a){return this.imagingHelper||(a=a||{},a.viewer=this,this.imagingHelper=new b.ImagingHelper(a)),this.imagingHelper},b.ImagingHelper=function(b){if(b=b||{},!b.viewer)throw new Error("A viewer must be specified.");if(b.viewer.imagingHelper)throw new Error("Viewer already has an ImagingHelper.");this._viewer=b.viewer,a.EventSource.call(this),this._viewer.imagingHelper=this,this.options=b,this.imgWidth=0,this.imgHeight=0,this.imgAspectRatio=0,this._zoomFactor=1,this._minZoom=.001,this._maxZoom=10,this._zoomStepPercent=30,this._haveImage=!1,this._viewerSize=null,this._viewportWidth=0,this._viewportHeight=0,this._viewportOrigin=new OpenSeadragon.Point(0,0),this._viewportCenter=new OpenSeadragon.Point(0,0),b.onImageViewChanged&&this.addHandler("image-view-changed",b.onImageViewChanged),this._viewer.addHandler("open",a.delegate(this,d)),this._viewer.addHandler("close",a.delegate(this,e)),this._viewer.addHandler("animation",a.delegate(this,f)),this._viewer.addHandler("animation-finish",a.delegate(this,g)),this._viewer.addHandler("resize",a.delegate(this,h)),this._viewer.addHandler("full-page",a.delegate(this,i)),this._viewer.addHandler("full-screen",a.delegate(this,j))},b.ImagingHelper.version={versionStr:"1.2.0",major:1,minor:2,revision:0},a.extend(b.ImagingHelper.prototype,a.EventSource.prototype,{_raiseImageViewChanged:function(){this.raiseEvent("image-view-changed",{viewportWidth:this._viewportWidth,viewportHeight:this._viewportHeight,viewportOrigin:this._viewportOrigin,viewportCenter:this._viewportCenter,zoomFactor:this._zoomFactor})},_trackZoomPan:function(){var a=this._viewer.viewport.getBounds(!0);this._viewportOrigin.x=a.x,this._viewportOrigin.y=a.y*this.imgAspectRatio,this._viewportWidth=a.width,this._viewportHeight=a.height*this.imgAspectRatio,this._viewportCenter.x=this._viewportOrigin.x+this._viewportWidth/2,this._viewportCenter.y=this._viewportOrigin.y+this._viewportHeight/2,this._zoomFactor=this.getViewerContainerSize().x/(this._viewportWidth*this.imgWidth),this._raiseImageViewChanged()},getViewerContainerSize:function(){var b=this._viewer.container;return new a.Point(b.clientWidth,b.clientHeight)},notifyResize:function(){var a,b,c;this._haveImage&&(a=this.getViewerContainerSize(),a.equals(this._viewerSize)||(this._viewerSize=a,b=new OpenSeadragon.Point(this._viewportCenter.x,this._viewportCenter.y/this.imgAspectRatio),c=this._zoomFactor,this._viewer.viewport.resize(a,!1),this._viewer.viewport.zoomTo(c*this.imgWidth/a.x,null,!0),this._viewer.viewport.panTo(b,!0),this._raiseImageViewChanged()))},getMinZoom:function(){return this._minZoom},setMinZoom:function(a){this._minZoom=a,this._viewer.minZoomLevel=a*this.imgWidth/this.getViewerContainerSize().x},getMaxZoom:function(){return this._maxZoom},setMaxZoom:function(a){this._maxZoom=a,this._viewer.maxZoomLevel=a*this.imgWidth/this.getViewerContainerSize().x},getZoomStepPercent:function(){return this._zoomStepPercent},setZoomStepPercent:function(a){this._zoomStepPercent=a},setView:function(a,b,c,d){this._haveImage&&((this._viewportWidth!=a||this._viewportHeight!=b)&&this._viewer.viewport.zoomTo(1/a,null,d),(this._viewportCenter.x!=c.x||this._viewportCenter.y!=c.y)&&this._viewer.viewport.panTo(new OpenSeadragon.Point(c.x,c.y/this.imgAspectRatio),d))},getZoomFactor:function(){return this._zoomFactor},setZoomFactor:function(a,b){this._haveImage&&a!=this._zoomFactor&&a>0&&this._viewer.viewport.zoomTo(a*this.imgWidth/this.getViewerContainerSize().x,new OpenSeadragon.Point(this._viewportCenter.x,this._viewportCenter.y/this.imgAspectRatio),b)},zoomIn:function(a){var b=this._zoomFactor;b*=1+this._zoomStepPercent/100,b>this._maxZoom&&(b=this._maxZoom),this.setZoomFactor(b,a)},zoomOut:function(a){var b=this._zoomFactor;b/=1+this._zoomStepPercent/100,b0&&this._viewer.viewport.zoomTo(a*this.imgWidth/this.getViewerContainerSize().x,new OpenSeadragon.Point(b.x,b.y/this.imgAspectRatio),c)},zoomInAboutLogicalPoint:function(a,b){var c=this._zoomFactor;c*=1+this._zoomStepPercent/100,c>this._maxZoom&&(c=this._maxZoom),this.zoomAboutLogicalPoint(c,a,b)},zoomOutAboutLogicalPoint:function(a,b){var c=this._zoomFactor;c/=1+this._zoomStepPercent/100,c0?a/this.imgWidth:0},dataToLogicalY:function(a){return this._haveImage&&this.imgHeight>0?a/this.imgHeight:0},physicalToDataX:function(a){return this._haveImage&&this.getViewerContainerSize().x>0?(this._viewportOrigin.x+a/this.getViewerContainerSize().x*this._viewportWidth)*this.imgWidth:0},physicalToDataY:function(a){return this._haveImage&&this.getViewerContainerSize().y>0?(this._viewportOrigin.y+a/this.getViewerContainerSize().y*this._viewportHeight)*this.imgHeight:0},dataToPhysicalX:function(a){return this._haveImage&&this.imgWidth>0?(a/this.imgWidth-this._viewportOrigin.x)/this._viewportWidth*this.getViewerContainerSize().x:0},dataToPhysicalY:function(a){return this._haveImage&&this.imgHeight>0?(a/this.imgHeight-this._viewportOrigin.y)/this._viewportHeight*this.getViewerContainerSize().y:0}})}(OpenSeadragon,window.OpenSeadragonImaging=window.OpenSeadragonImaging||{}); \ No newline at end of file diff --git a/js/openseadragon/openseadragon-scalebar.BAK.js b/js/openseadragon/openseadragon-scalebar.BAK.js new file mode 100644 index 000000000..56f947f6d --- /dev/null +++ b/js/openseadragon/openseadragon-scalebar.BAK.js @@ -0,0 +1,469 @@ +/* + * This software was developed at the National Institute of Standards and + * Technology by employees of the Federal Government in the course of + * their official duties. Pursuant to title 17 Section 105 of the United + * States Code this software is not subject to copyright protection and is + * in the public domain. This software is an experimental system. NIST assumes + * no responsibility whatsoever for its use by other parties, and makes no + * guarantees, expressed or implied, about its quality, reliability, or + * any other characteristic. We would appreciate acknowledgement if the + * software is used. + */ + +/** + * + * @author Antoine Vandecreme + */ +(function($) { + + if (!$.version || $.version.major < 1) { + throw new Error('OpenSeadragonScalebar requires OpenSeadragon version 1.0.0+'); + } + + $.Viewer.prototype.scalebar = function(options) { + if (!this.scalebarInstance) { + options = options || {}; + options.viewer = this; + this.scalebarInstance = new $.Scalebar(options); + } else { + this.scalebarInstance.refresh(options); + } + }; + + $.ScalebarType = { + NONE: 0, + MICROSCOPY: 1, + MAP: 2 + }; + + $.ScalebarLocation = { + NONE: 0, + TOP_LEFT: 1, + TOP_RIGHT: 2, + BOTTOM_RIGHT: 3, + BOTTOM_LEFT: 4 + }; + + /** + * + * @class Scalebar + * @param {Object} options + * @param {OpenSeadragon.Viewer} options.viewer The viewer to attach this + * Scalebar to. + * @param {OpenSeadragon.ScalebarType} options.type The scale bar type. + * Default: microscopy + * @param {Integer} options.pixelsPerMeter The pixels per meter of the + * zoomable image at the original image size. If null, the scale bar is not + * displayed. default: null + * @param (String} options.minWidth The minimal width of the scale bar as a + * CSS string (ex: 100px, 1em, 1% etc...) default: 150px + * @param {OpenSeadragon.ScalebarLocation} options.location The location + * of the scale bar inside the viewer. default: bottom left + * @param {Integer} options.xOffset Offset location of the scale bar along x. + * default: 5 + * @param {Integer} options.yOffset Offset location of the scale bar along y. + * default: 5 + * @param {Boolean} options.stayInsideImage When set to true, keep the + * scale bar inside the image when zooming out. default: true + * @param {String} options.color The color of the scale bar using a color + * name or the hexadecimal format (ex: black or #000000) default: black + * @param {String} options.fontColor The font color. default: black + * @param {String} options.backgroundColor The background color. default: none + * @param {String} options.fontSize The font size. default: not set + * @param {String} options.barThickness The thickness of the scale bar in px. + * default: 2 + * @param {function} options.sizeAndTextRenderer A function which will be + * called to determine the size of the scale bar and it's text content. + * The function must have 2 parameters: the PPM at the current zoom level + * and the minimum size of the scale bar. It must return an object containing + * 2 attributes: size and text containing the size of the scale bar and the text. + * default: $.ScalebarSizeAndTextRenderer.METRIC_LENGTH + */ + $.Scalebar = function(options) { + options = options || {}; + if (!options.viewer) { + throw new Error("A viewer must be specified."); + } + this.viewer = options.viewer; + + this.divElt = document.createElement("div"); + this.viewer.container.appendChild(this.divElt); + this.divElt.style.position = "relative"; + this.divElt.style.margin = "0"; + + this.setMinWidth(options.minWidth || "150px"); + + this.setDrawScalebarFunction(options.type || $.ScalebarType.MICROSCOPY); + this.color = options.color || "black"; + this.fontColor = options.fontColor || "black"; + this.backgroundColor = options.backgroundColor || "none"; + this.fontSize = options.fontSize || ""; + this.barThickness = options.barThickness || 2; + this.pixelsPerMeter = options.pixelsPerMeter || null; + this.location = options.location || $.ScalebarLocation.BOTTOM_LEFT; + this.xOffset = options.xOffset || 5; + this.yOffset = options.yOffset || 5; + this.stayInsideImage = isDefined(options.stayInsideImage) ? + options.stayInsideImage : true; + this.sizeAndTextRenderer = options.sizeAndTextRenderer || + $.ScalebarSizeAndTextRenderer.METRIC_LENGTH; + + var self = this; + this.viewer.addHandler("open", function() { + self.refresh(); + }); + this.viewer.addHandler("animation", function() { + self.refresh(); + }); + }; + + $.Scalebar.prototype = { + updateOptions: function(options) { + if (!options) { + return; + } + if (isDefined(options.type)) { + this.setDrawScalebarFunction(options.type); + } + if (isDefined(options.minWidth)) { + this.setMinWidth(options.minWidth); + } + if (isDefined(options.color)) { + this.color = options.color; + } + if (isDefined(options.fontColor)) { + this.fontColor = options.fontColor; + } + if (isDefined(options.backgroundColor)) { + this.backgroundColor = options.backgroundColor; + } + if (isDefined(options.fontSize)) { + this.fontSize = options.fontSize; + } + if (isDefined(options.barThickness)) { + this.barThickness = options.barThickness; + } + if (isDefined(options.pixelsPerMeter)) { + this.pixelsPerMeter = options.pixelsPerMeter; + } + if (isDefined(options.location)) { + this.location = options.location; + } + if (isDefined(options.xOffset)) { + this.xOffset = options.xOffset; + } + if (isDefined(options.yOffset)) { + this.yOffset = options.yOffset; + } + if (isDefined(options.stayInsideImage)) { + this.stayInsideImage = options.stayInsideImage; + } + if (isDefined(options.sizeAndTextRenderer)) { + this.sizeAndTextRenderer = options.sizeAndTextRenderer; + } + }, + setDrawScalebarFunction: function(type) { + if (!type) { + this.drawScalebar = null; + } + else if (type === $.ScalebarType.MAP) { + this.drawScalebar = this.drawMapScalebar; + } else { + this.drawScalebar = this.drawMicroscopyScalebar; + } + }, + setMinWidth: function(minWidth) { + this.divElt.style.width = minWidth; + // Make sure to display the element before getting is width + this.divElt.style.display = ""; + this.minWidth = this.divElt.offsetWidth; + }, + /** + * Refresh the scalebar with the options submitted. + * @param {Object} options + * @param {OpenSeadragon.ScalebarType} options.type The scale bar type. + * Default: microscopy + * @param {Integer} options.pixelsPerMeter The pixels per meter of the + * zoomable image at the original image size. If null, the scale bar is not + * displayed. default: null + * @param (String} options.minWidth The minimal width of the scale bar as a + * CSS string (ex: 100px, 1em, 1% etc...) default: 150px + * @param {OpenSeadragon.ScalebarLocation} options.location The location + * of the scale bar inside the viewer. default: bottom left + * @param {Integer} options.xOffset Offset location of the scale bar along x. + * default: 5 + * @param {Integer} options.yOffset Offset location of the scale bar along y. + * default: 5 + * @param {Boolean} options.stayInsideImage When set to true, keep the + * scale bar inside the image when zooming out. default: true + * @param {String} options.color The color of the scale bar using a color + * name or the hexadecimal format (ex: black or #000000) default: black + * @param {String} options.fontColor The font color. default: black + * @param {String} options.backgroundColor The background color. default: none + * @param {String} options.fontSize The font size. default: not set + * @param {String} options.barThickness The thickness of the scale bar in px. + * default: 2 + * @param {function} options.sizeAndTextRenderer A function which will be + * called to determine the size of the scale bar and it's text content. + * The function must have 2 parameters: the PPM at the current zoom level + * and the minimum size of the scale bar. It must return an object containing + * 2 attributes: size and text containing the size of the scale bar and the text. + * default: $.ScalebarSizeAndTextRenderer.METRIC_LENGTH + */ + refresh: function(options) { + this.updateOptions(options); + + if (!this.viewer.isOpen() || + !this.drawScalebar || + !this.pixelsPerMeter || + !this.location) { + this.divElt.style.display = "none"; + return; + } + this.divElt.style.display = ""; + + var viewport = this.viewer.viewport; + var zoom = viewport.viewportToImageZoom(viewport.getZoom(true)); + var currentPPM = zoom * this.pixelsPerMeter; + var props = this.sizeAndTextRenderer(currentPPM, this.minWidth); + + this.drawScalebar(props.size, props.text); + var location = this.getScalebarLocation(); + this.divElt.style.left = location.x + "px"; + this.divElt.style.top = location.y + "px"; + }, + drawMicroscopyScalebar: function(size, text) { + this.divElt.style.fontSize = this.fontSize; + this.divElt.style.textAlign = "center"; + this.divElt.style.color = this.fontColor; + this.divElt.style.border = "none"; + this.divElt.style.borderBottom = this.barThickness + "px solid " + this.color; + this.divElt.style.backgroundColor = this.backgroundColor; + this.divElt.innerHTML = text; + this.divElt.style.width = size + "px"; + }, + drawMapScalebar: function(size, text) { + this.divElt.style.fontSize = this.fontSize; + this.divElt.style.textAlign = "center"; + this.divElt.style.color = this.fontColor; + this.divElt.style.border = this.barThickness + "px solid " + this.color; + this.divElt.style.borderTop = "none"; + this.divElt.style.backgroundColor = this.backgroundColor; + this.divElt.innerHTML = text; + this.divElt.style.width = size + "px"; + }, + /** + * Compute the location of the scale bar. + * @returns {OpenSeadragon.Point} + */ + getScalebarLocation: function() { + if (this.location === $.ScalebarLocation.TOP_LEFT) { + var x = 0; + var y = 0; + if (this.stayInsideImage) { + var pixel = this.viewer.viewport.pixelFromPoint( + new $.Point(0, 0), true); + if (!this.viewer.wrapHorizontal) { + x = Math.max(pixel.x, 0); + } + if (!this.viewer.wrapVertical) { + y = Math.max(pixel.y, 0); + } + } + return new $.Point(x + this.xOffset, y + this.yOffset); + } + if (this.location === $.ScalebarLocation.TOP_RIGHT) { + var barWidth = this.divElt.offsetWidth; + var container = this.viewer.container; + var x = container.offsetWidth - barWidth; + var y = 0; + if (this.stayInsideImage) { + var pixel = this.viewer.viewport.pixelFromPoint( + new $.Point(1, 0), true); + if (!this.viewer.wrapHorizontal) { + x = Math.min(x, pixel.x - barWidth); + } + if (!this.viewer.wrapVertical) { + y = Math.max(y, pixel.y); + } + } + return new $.Point(x - this.xOffset, y + this.yOffset); + } + if (this.location === $.ScalebarLocation.BOTTOM_RIGHT) { + var barWidth = this.divElt.offsetWidth; + var barHeight = this.divElt.offsetHeight; + var container = this.viewer.container; + var x = container.offsetWidth - barWidth; + var y = container.offsetHeight - barHeight; + if (this.stayInsideImage) { + var pixel = this.viewer.viewport.pixelFromPoint( + new $.Point(1, 1 / this.viewer.source.aspectRatio), + true); + if (!this.viewer.wrapHorizontal) { + x = Math.min(x, pixel.x - barWidth); + } + if (!this.viewer.wrapVertical) { + y = Math.min(y, pixel.y - barHeight); + } + } + return new $.Point(x - this.xOffset, y - this.yOffset); + } + if (this.location === $.ScalebarLocation.BOTTOM_LEFT) { + var barHeight = this.divElt.offsetHeight; + var container = this.viewer.container; + var x = 0; + var y = container.offsetHeight - barHeight; + if (this.stayInsideImage) { + var pixel = this.viewer.viewport.pixelFromPoint( + new $.Point(0, 1 / this.viewer.source.aspectRatio), + true); + if (!this.viewer.wrapHorizontal) { + x = Math.max(x, pixel.x); + } + if (!this.viewer.wrapVertical) { + y = Math.min(y, pixel.y - barHeight); + } + } + return new $.Point(x + this.xOffset, y - this.yOffset); + } + } + }; + + $.ScalebarSizeAndTextRenderer = { + /** + * Metric length. From nano meters to kilometers. + */ + METRIC_LENGTH: function(ppm, minSize) { + return getScalebarSizeAndTextForMetric(ppm, minSize, "m"); + }, + /** + * Imperial length. Choosing the best unit from thou, inch, foot and mile. + */ + IMPERIAL_LENGTH: function(ppm, minSize) { + var maxSize = minSize * 2; + var ppi = ppm * 0.0254; + if (maxSize < ppi * 12) { + if (maxSize < ppi) { + var ppt = ppi / 1000; + return getScalebarSizeAndText(ppt, minSize, "th"); + } + return getScalebarSizeAndText(ppi, minSize, "in"); + } + var ppf = ppi * 12; + if (maxSize < ppf * 2000) { + return getScalebarSizeAndText(ppf, minSize, "ft"); + } + var ppmi = ppf * 5280; + return getScalebarSizeAndText(ppmi, minSize, "mi"); + }, + /** + * Standard time. Choosing the best unit from second (and metric divisions), + * minute, hour, day and year. + */ + STANDARD_TIME: function(pps, minSize) { + var maxSize = minSize * 2; + if (maxSize < pps * 60) { + return getScalebarSizeAndTextForMetric(pps, minSize, "s"); + } + var ppminutes = pps * 60; + if (maxSize < ppminutes * 60) { + return getScalebarSizeAndText(ppminutes, minSize, "minute"); + } + var pph = ppminutes * 60; + if (maxSize < pph * 24) { + return getScalebarSizeAndText(pph, minSize, "hour"); + } + var ppd = pph * 24; + if (maxSize < ppd * 365.25) { + return getScalebarSizeAndText(ppd, minSize, "day"); + } + var ppy = ppd * 365.25; + return getScalebarSizeAndText(ppy, minSize, "year"); + }, + /** + * Generic metric unit. One can use this function to create a new metric + * scale. For example, here is an implementation of energy levels: + * function(ppeV, minSize) { + * return OpenSeadragon.ScalebarSizeAndTextRenderer.METRIC_GENERIC( + * ppeV, minSize, "eV"); + * } + */ + METRIC_GENERIC: getScalebarSizeAndTextForMetric + }; + + function getScalebarSizeAndText(ppm, minSize, unitSuffix) { + var value = normalize(ppm, minSize); + var factor = roundSignificand(value / ppm * minSize, 3); + var size = value * minSize; + return { + size: size, + text: factor + " " + unitSuffix + }; + } + + function getScalebarSizeAndTextForMetric(ppm, minSize, unitSuffix) { + var value = normalize(ppm, minSize); + var factor = roundSignificand(value / ppm * minSize, 3); + var size = value * minSize; + var valueWithUnit = getWithUnit(factor, unitSuffix); + return { + size: size, + text: valueWithUnit + }; + } + + function normalize(value, minSize) { + var significand = getSignificand(value); + var minSizeSign = getSignificand(minSize); + var result = getSignificand(significand / minSizeSign); + if (result >= 5) { + result /= 5; + } + if (result >= 4) { + result /= 4; + } + if (result >= 2) { + result /= 2; + } + return result; + } + + function getSignificand(x) { + return x * Math.pow(10, Math.ceil(-log10(x))); + } + + function roundSignificand(x, decimalPlaces) { + var exponent = -Math.ceil(-log10(x)); + var power = decimalPlaces - exponent; + var significand = x * Math.pow(10, power); + // To avoid rounding problems, always work with integers + if (power < 0) { + return Math.round(significand) * Math.pow(10, -power); + } + return Math.round(significand) / Math.pow(10, power); + } + + function log10(x) { + return Math.log(x) / Math.log(10); + } + + function getWithUnit(value, unitSuffix) { + if (value < 0.000001) { + return value * 100000000 + " n" + unitSuffix; + } + if (value < 0.001) { + return value * 1000000 + " μ" + unitSuffix; + } + if (value < 1) { + return value * 1000 + " m" + unitSuffix; + } + if (value >= 1000) { + return value / 1000 + " k" + unitSuffix; + } + return value + " " + unitSuffix; + } + + function isDefined(variable) { + return typeof (variable) !== "undefined"; + } +}(OpenSeadragon)); diff --git a/js/openseadragon/openseadragon-scalebar.js b/js/openseadragon/openseadragon-scalebar.js index 56f947f6d..f192db6f6 100644 --- a/js/openseadragon/openseadragon-scalebar.js +++ b/js/openseadragon/openseadragon-scalebar.js @@ -16,8 +16,9 @@ */ (function($) { - if (!$.version || $.version.major < 1) { - throw new Error('OpenSeadragonScalebar requires OpenSeadragon version 1.0.0+'); + if (!$.version || $.version.major < 2) { + throw new Error('This version of OpenSeadragonScalebar requires ' + + 'OpenSeadragon version 2.0.0+'); } $.Viewer.prototype.scalebar = function(options) { @@ -55,6 +56,9 @@ * @param {Integer} options.pixelsPerMeter The pixels per meter of the * zoomable image at the original image size. If null, the scale bar is not * displayed. default: null + * @param {Integer} options.referenceItemIdx Specify the item from + * viewer.world to which options.pixelsPerMeter is refering. + * default: 0 * @param (String} options.minWidth The minimal width of the scale bar as a * CSS string (ex: 100px, 1em, 1% etc...) default: 150px * @param {OpenSeadragon.ScalebarLocation} options.location The location @@ -70,6 +74,7 @@ * @param {String} options.fontColor The font color. default: black * @param {String} options.backgroundColor The background color. default: none * @param {String} options.fontSize The font size. default: not set + * @param {String} options.fontFamily The font-family. default: not set * @param {String} options.barThickness The thickness of the scale bar in px. * default: 2 * @param {function} options.sizeAndTextRenderer A function which will be @@ -90,6 +95,7 @@ this.viewer.container.appendChild(this.divElt); this.divElt.style.position = "relative"; this.divElt.style.margin = "0"; + this.divElt.style.pointerEvents = "none"; this.setMinWidth(options.minWidth || "150px"); @@ -98,8 +104,10 @@ this.fontColor = options.fontColor || "black"; this.backgroundColor = options.backgroundColor || "none"; this.fontSize = options.fontSize || ""; + this.fontFamily = options.fontFamily || ""; this.barThickness = options.barThickness || 2; this.pixelsPerMeter = options.pixelsPerMeter || null; + this.referenceItemIdx = options.referenceItemIdx || 0; this.location = options.location || $.ScalebarLocation.BOTTOM_LEFT; this.xOffset = options.xOffset || 5; this.yOffset = options.yOffset || 5; @@ -115,6 +123,9 @@ this.viewer.addHandler("animation", function() { self.refresh(); }); + this.viewer.addHandler("resize", function() { + self.refresh(); + }); }; $.Scalebar.prototype = { @@ -140,12 +151,18 @@ if (isDefined(options.fontSize)) { this.fontSize = options.fontSize; } + if (isDefined(options.fontFamily)) { + this.fontFamily = options.fontFamily; + } if (isDefined(options.barThickness)) { this.barThickness = options.barThickness; } if (isDefined(options.pixelsPerMeter)) { this.pixelsPerMeter = options.pixelsPerMeter; } + if (isDefined(options.referenceItemIdx)) { + this.referenceItemIdx = options.referenceItemIdx; + } if (isDefined(options.location)) { this.location = options.location; } @@ -186,6 +203,9 @@ * @param {Integer} options.pixelsPerMeter The pixels per meter of the * zoomable image at the original image size. If null, the scale bar is not * displayed. default: null + * @param {Integer} options.referenceItemIdx Specify the item from + * viewer.world to which options.pixelsPerMeter is refering. + * default: 0 * @param (String} options.minWidth The minimal width of the scale bar as a * CSS string (ex: 100px, 1em, 1% etc...) default: 150px * @param {OpenSeadragon.ScalebarLocation} options.location The location @@ -223,7 +243,9 @@ this.divElt.style.display = ""; var viewport = this.viewer.viewport; - var zoom = viewport.viewportToImageZoom(viewport.getZoom(true)); + var tiledImage = this.viewer.world.getItemAt(this.referenceItemIdx); + var zoom = tiledImageViewportToImageZoom(tiledImage, + viewport.getZoom(true)); var currentPPM = zoom * this.pixelsPerMeter; var props = this.sizeAndTextRenderer(currentPPM, this.minWidth); @@ -234,6 +256,7 @@ }, drawMicroscopyScalebar: function(size, text) { this.divElt.style.fontSize = this.fontSize; + this.divElt.style.fontFamily = this.fontFamily; this.divElt.style.textAlign = "center"; this.divElt.style.color = this.fontColor; this.divElt.style.border = "none"; @@ -244,6 +267,7 @@ }, drawMapScalebar: function(size, text) { this.divElt.style.fontSize = this.fontSize; + this.divElt.style.fontFamily = this.fontFamily; this.divElt.style.textAlign = "center"; this.divElt.style.color = this.fontColor; this.divElt.style.border = this.barThickness + "px solid " + this.color; @@ -326,6 +350,50 @@ } return new $.Point(x + this.xOffset, y - this.yOffset); } + }, + /** + * Get the rendered scalebar in a canvas. + * @returns {Element} A canvas containing the scalebar representation + */ + getAsCanvas: function() { + var canvas = document.createElement("canvas"); + canvas.width = this.divElt.offsetWidth; + canvas.height = this.divElt.offsetHeight; + var context = canvas.getContext("2d"); + context.fillStyle = this.backgroundColor; + context.fillRect(0, 0, canvas.width, canvas.height); + context.fillStyle = this.color; + context.fillRect(0, canvas.height - this.barThickness, + canvas.width, canvas.height); + if (this.drawScalebar === this.drawMapScalebar) { + context.fillRect(0, 0, this.barThickness, canvas.height); + context.fillRect(canvas.width - this.barThickness, 0, + this.barThickness, canvas.height); + } + context.font = window.getComputedStyle(this.divElt).font; + context.textAlign = "center"; + context.textBaseline = "middle"; + context.fillStyle = this.fontColor; + var hCenter = canvas.width / 2; + var vCenter = canvas.height / 2; + context.fillText(this.divElt.textContent, hCenter, vCenter); + return canvas; + }, + /** + * Get a copy of the current OpenSeadragon canvas with the scalebar. + * @returns {Element} A canvas containing a copy of the current OpenSeadragon canvas with the scalebar + */ + getImageWithScalebarAsCanvas: function() { + var imgCanvas = this.viewer.drawer.canvas; + var newCanvas = document.createElement("canvas"); + newCanvas.width = imgCanvas.width; + newCanvas.height = imgCanvas.height; + var newCtx = newCanvas.getContext("2d"); + newCtx.drawImage(imgCanvas, 0, 0); + var scalebarCanvas = this.getAsCanvas(); + var location = this.getScalebarLocation(); + newCtx.drawImage(scalebarCanvas, location.x, location.y); + return newCanvas; } }; @@ -356,6 +424,21 @@ var ppmi = ppf * 5280; return getScalebarSizeAndText(ppmi, minSize, "mi"); }, + /** + * Astronomy units. Choosing the best unit from arcsec, arcminute, and degree + */ + ASTRONOMY: function(ppa, minSize) { + var maxSize = minSize * 2; + if (maxSize < ppa * 60) { + return getScalebarSizeAndText(ppa, minSize, "\"", false, ''); + } + var ppminutes = ppa * 60; + if (maxSize < ppminutes * 60) { + return getScalebarSizeAndText(ppminutes, minSize, "\'", false, ''); + } + var ppd = ppminutes * 60; + return getScalebarSizeAndText(ppd, minSize, "°", false, ''); + }, /** * Standard time. Choosing the best unit from second (and metric divisions), * minute, hour, day and year. @@ -363,22 +446,22 @@ STANDARD_TIME: function(pps, minSize) { var maxSize = minSize * 2; if (maxSize < pps * 60) { - return getScalebarSizeAndTextForMetric(pps, minSize, "s"); + return getScalebarSizeAndTextForMetric(pps, minSize, "s", false); } var ppminutes = pps * 60; if (maxSize < ppminutes * 60) { - return getScalebarSizeAndText(ppminutes, minSize, "minute"); + return getScalebarSizeAndText(ppminutes, minSize, "minute", true); } var pph = ppminutes * 60; if (maxSize < pph * 24) { - return getScalebarSizeAndText(pph, minSize, "hour"); + return getScalebarSizeAndText(pph, minSize, "hour", true); } var ppd = pph * 24; if (maxSize < ppd * 365.25) { - return getScalebarSizeAndText(ppd, minSize, "day"); + return getScalebarSizeAndText(ppd, minSize, "day", true); } var ppy = ppd * 365.25; - return getScalebarSizeAndText(ppy, minSize, "year"); + return getScalebarSizeAndText(ppy, minSize, "year", true); }, /** * Generic metric unit. One can use this function to create a new metric @@ -391,13 +474,23 @@ METRIC_GENERIC: getScalebarSizeAndTextForMetric }; - function getScalebarSizeAndText(ppm, minSize, unitSuffix) { + // Missing TiledImage.viewportToImageZoom function in OSD 2.0.0 + function tiledImageViewportToImageZoom(tiledImage, viewportZoom) { + var ratio = tiledImage._scaleSpring.current.value * + tiledImage.viewport._containerInnerSize.x / + tiledImage.source.dimensions.x; + return ratio * viewportZoom; + } + + function getScalebarSizeAndText(ppm, minSize, unitSuffix, handlePlural, spacer) { + spacer = spacer === undefined ? ' ' : spacer; var value = normalize(ppm, minSize); var factor = roundSignificand(value / ppm * minSize, 3); var size = value * minSize; + var plural = handlePlural && factor > 1 ? "s" : ""; return { size: size, - text: factor + " " + unitSuffix + text: factor + spacer + unitSuffix + plural }; } @@ -449,7 +542,7 @@ function getWithUnit(value, unitSuffix) { if (value < 0.000001) { - return value * 100000000 + " n" + unitSuffix; + return value * 1000000000 + " n" + unitSuffix; } if (value < 0.001) { return value * 1000000 + " μ" + unitSuffix; diff --git a/js/openseadragon/openseadragonzoomlevels.BAK.js b/js/openseadragon/openseadragonzoomlevels.BAK.js new file mode 100644 index 000000000..1fb43dea3 --- /dev/null +++ b/js/openseadragon/openseadragonzoomlevels.BAK.js @@ -0,0 +1 @@ +!function(e){"use strict";function o(o){e.isArray(o)&&o.sort(function(e,o){return e-o})}if(!e.version||e.version.major<2)throw new Error("This version of OpenSeadragonZoomLevels requires OpenSeadragon version 2.0.0+");e.Viewer.prototype.zoomLevels=function(o){return(!this.zoomLevelsInstance||o)&&(o=o||{},o.viewer=this,this.zoomLevelsInstance=new e.ZoomLevels(o)),this.zoomLevelsInstance},e.ZoomLevels=function(r){var t=this;e.extend(!0,t,{viewer:null,levels:[]},r),o(r.levels);var i,s=t.viewer.viewport;t.viewer.addHandler("zoom",function(e){i!==e.zoom&&(i=e.zoom,i!==s.getHomeZoom()&&(is.zoomSpring.current.value&&(i=t.getUpperZoomLevel(i))),i!==e.zoom&&(e.zoom=i,s.zoomTo(i,e.refPoint,e.immediately)))})},e.extend(e.ZoomLevels.prototype,{getUpperZoomLevel:function(o){if(e.isArray(this.levels)&&this.levels.length){var r=this.viewer.viewport,t=r.viewportToImageZoom(o);o=r.imageToViewportZoom(this.levels[this.levels.length-1]);for(var i=0;it){o=r.imageToViewportZoom(this.levels[i]);break}return Math.min(o,r.getMaxZoom())}return o},getLowerZoomLevel:function(o){if(e.isArray(this.levels)&&this.levels.length){var r=this.viewer.viewport,t=r.viewportToImageZoom(o);o=r.imageToViewportZoom(this.levels[0]);for(var i=this.levels.length-1;i>=0;i--)if(this.levels[i]s.zoomSpring.current.value&&(i=t.getUpperZoomLevel(i))),i!==e.zoom&&(e.zoom=i,s.zoomTo(i,e.refPoint,e.immediately)))})},e.extend(e.ZoomLevels.prototype,{getUpperZoomLevel:function(o){if(e.isArray(this.levels)&&this.levels.length){var r=this.viewer.viewport,t=r.viewportToImageZoom(o);o=r.imageToViewportZoom(this.levels[this.levels.length-1]);for(var i=0;it){o=r.imageToViewportZoom(this.levels[i]);break}return Math.min(o,r.getMaxZoom())}return o},getLowerZoomLevel:function(o){if(e.isArray(this.levels)&&this.levels.length){var r=this.viewer.viewport,t=r.viewportToImageZoom(o);o=r.imageToViewportZoom(this.levels[0]);for(var i=this.levels.length-1;i>=0;i--)if(this.levels[i]s.zoomSpring.current.value&&(i=r.getUpperZoomLevel(i))),i!==e.zoom&&(e.zoom=i,s.zoomTo(i,e.refPoint,e.immediately)))})},e.extend(e.ZoomLevels.prototype,{getUpperZoomLevel:function(o){if(e.isArray(this.levels)&&this.levels.length){var t=this.viewer.world.getItemAt(0),r=t.viewportToImageZoom(o);o=t.imageToViewportZoom(this.levels[this.levels.length-1]);for(var i=0;i=r){o=t.imageToViewportZoom(this.levels[i]);break}return Math.min(o,this.viewer.viewport.getMaxZoom())}return o},getLowerZoomLevel:function(o){if(e.isArray(this.levels)&&this.levels.length){var t=this.viewer.world.getItemAt(0),r=t.viewportToImageZoom(o);o=t.imageToViewportZoom(this.levels[0]);for(var i=this.levels.length-1;i>=0;i--)if(this.levels[i]<=r){o=t.imageToViewportZoom(this.levels[i]);break}return Math.max(o,this.viewer.viewport.getMinZoom())}return o}})}(OpenSeadragon); +//# sourceMappingURL=openseadragonzoomlevels.js.map diff --git a/js/tile_overlays/tile_overlays.js b/js/tile_overlays/tile_overlays.js new file mode 100644 index 000000000..41ef72f83 --- /dev/null +++ b/js/tile_overlays/tile_overlays.js @@ -0,0 +1,144 @@ +var overlays = function (tissueId, viewer) { + this.tissueId = tissueId; + this.viewer = viewer; + this.m_tilesize = 256; + this.m_minlevel = 0; //m_minlevel = ln(m_tilesize)/ln(2) + this.m_overlaymaxlevel = 6; +}; + +/** + * Segmentation tile overlay. + * + * @param imgData + */ +overlays.prototype.overlayRoutine = function (imgData) { + var self = this; + var viewer = self.viewer; + + var tilename = tissueId; + if (imgData.name) + { + tilename = imgData.name; + } + + var odata = { + tilesize: self.m_tilesize, + minlevel: self.m_minlevel, + maxlevel: self.m_overlaymaxlevel, + width: imgData.w, + height: imgData.h, + name: tilename, + loc: imgData.loc + }; + + try { + viewer.addTiledImage({ + tileSource: { + height: odata.height, + width: odata.width, + tileSize: odata.tilesize, + minLevel: odata.minlevel, + maxLevel: odata.maxlevel, + getTileUrl: function (level, x, y) { + return location.origin + self.getPath(odata.loc) + odata.name + "-" + (odata.maxlevel - level) + "-" + x + "-" + y + ".png"; + + } + } + }); + } catch (e) { + throw ('Error generating overlays ' + e.message); + } +}; + + +/** + * Get web path from file path + * + * @param overlayFolder + * @returns {string} + */ +overlays.prototype.getPath = function (overlayFolder) { + return ('/overlays/' + overlayFolder.split(/[/ ]+/).pop() + '/'); +}; + + +/** + * Toggle OFF. + */ +overlays.prototype.toggleAllOFF = function () { + + var tiledImage; + while (viewer.world.getItemCount() > 1) { + tiledImage = viewer.world.getItemAt(1); + tiledImage.setOpacity(0); + viewer.world.removeItem(tiledImage); + } + +}; + +/** + * Toggle tile segmentation on/off. + * + * @param OVERLAY_LIST + * @param SELECTED_ALGORITHM_LIST + */ +overlays.prototype.toggle = function (OVERLAY_LIST, SELECTED_ALGORITHM_LIST) { + + var self = this; + + // Turn off segmentation. + self.toggleAllOFF(); + + // Turn on segmentation. + OVERLAY_LIST.forEach(function (elem) { + + // Find available-tile in selected-list + var idx = SELECTED_ALGORITHM_LIST.indexOf(elem.execid); + + // element is selected + if (idx >= 0) { + + var imgData = { + "id": self.tissueId, + "w": imagingHelper.imgWidth, + "h": imagingHelper.imgHeight, + "loc": elem.loc, + "name": elem.name + }; + self.overlayRoutine(imgData); + + } + }); + +}; + +/** + * Get available overlays. + * + * @param algorithms_urlparam + */ +overlays.prototype.getList = function (algorithms_urlparam) { + /** + * Populate available-overlays array. + */ + jQuery.get("api/Data/getOverlayTiles.php?iid=" + self.tissueId + "&algorithms=" + algorithms_urlparam, function (data) { + + var d = JSON.parse(data); + for (var i = 0; i < d.length; i++) { + if (d[i]['tile-location'] != null) { + var myObj = {}; + myObj.execid = d[i].provenance.analysis_execution_id; + myObj.loc = d[i]['tile-location']; + myObj.name = d[i]['tile_name']; + OVERLAY_LIST.push(myObj); + } + else { + console.log(d[i], "has no tile location") + } + } + console.log("OVERLAY_LIST", OVERLAY_LIST); + + }); + + return OVERLAY_LIST; +}; diff --git a/js/wNumb.js b/js/wNumb.js new file mode 100644 index 000000000..4ab340fe5 --- /dev/null +++ b/js/wNumb.js @@ -0,0 +1,357 @@ +(function (factory) { + + if ( typeof define === 'function' && define.amd ) { + + // AMD. Register as an anonymous module. + define([], factory); + + } else if ( typeof exports === 'object' ) { + + // Node/CommonJS + module.exports = factory(); + + } else { + + // Browser globals + window.wNumb = factory(); + } + +}(function(){ + + 'use strict'; + +var FormatOptions = [ + 'decimals', + 'thousand', + 'mark', + 'prefix', + 'suffix', + 'encoder', + 'decoder', + 'negativeBefore', + 'negative', + 'edit', + 'undo' +]; + +// General + + // Reverse a string + function strReverse ( a ) { + return a.split('').reverse().join(''); + } + + // Check if a string starts with a specified prefix. + function strStartsWith ( input, match ) { + return input.substring(0, match.length) === match; + } + + // Check is a string ends in a specified suffix. + function strEndsWith ( input, match ) { + return input.slice(-1 * match.length) === match; + } + + // Throw an error if formatting options are incompatible. + function throwEqualError( F, a, b ) { + if ( (F[a] || F[b]) && (F[a] === F[b]) ) { + throw new Error(a); + } + } + + // Check if a number is finite and not NaN + function isValidNumber ( input ) { + return typeof input === 'number' && isFinite( input ); + } + + // Provide rounding-accurate toFixed method. + // Borrowed: http://stackoverflow.com/a/21323330/775265 + function toFixed ( value, exp ) { + value = value.toString().split('e'); + value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp))); + value = value.toString().split('e'); + return (+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp))).toFixed(exp); + } + + +// Formatting + + // Accept a number as input, output formatted string. + function formatTo ( decimals, thousand, mark, prefix, suffix, encoder, decoder, negativeBefore, negative, edit, undo, input ) { + + var originalInput = input, inputIsNegative, inputPieces, inputBase, inputDecimals = '', output = ''; + + // Apply user encoder to the input. + // Expected outcome: number. + if ( encoder ) { + input = encoder(input); + } + + // Stop if no valid number was provided, the number is infinite or NaN. + if ( !isValidNumber(input) ) { + return false; + } + + // Rounding away decimals might cause a value of -0 + // when using very small ranges. Remove those cases. + if ( decimals !== false && parseFloat(input.toFixed(decimals)) === 0 ) { + input = 0; + } + + // Formatting is done on absolute numbers, + // decorated by an optional negative symbol. + if ( input < 0 ) { + inputIsNegative = true; + input = Math.abs(input); + } + + // Reduce the number of decimals to the specified option. + if ( decimals !== false ) { + input = toFixed( input, decimals ); + } + + // Transform the number into a string, so it can be split. + input = input.toString(); + + // Break the number on the decimal separator. + if ( input.indexOf('.') !== -1 ) { + inputPieces = input.split('.'); + + inputBase = inputPieces[0]; + + if ( mark ) { + inputDecimals = mark + inputPieces[1]; + } + + } else { + + // If it isn't split, the entire number will do. + inputBase = input; + } + + // Group numbers in sets of three. + if ( thousand ) { + inputBase = strReverse(inputBase).match(/.{1,3}/g); + inputBase = strReverse(inputBase.join( strReverse( thousand ) )); + } + + // If the number is negative, prefix with negation symbol. + if ( inputIsNegative && negativeBefore ) { + output += negativeBefore; + } + + // Prefix the number + if ( prefix ) { + output += prefix; + } + + // Normal negative option comes after the prefix. Defaults to '-'. + if ( inputIsNegative && negative ) { + output += negative; + } + + // Append the actual number. + output += inputBase; + output += inputDecimals; + + // Apply the suffix. + if ( suffix ) { + output += suffix; + } + + // Run the output through a user-specified post-formatter. + if ( edit ) { + output = edit ( output, originalInput ); + } + + // All done. + return output; + } + + // Accept a sting as input, output decoded number. + function formatFrom ( decimals, thousand, mark, prefix, suffix, encoder, decoder, negativeBefore, negative, edit, undo, input ) { + + var originalInput = input, inputIsNegative, output = ''; + + // User defined pre-decoder. Result must be a non empty string. + if ( undo ) { + input = undo(input); + } + + // Test the input. Can't be empty. + if ( !input || typeof input !== 'string' ) { + return false; + } + + // If the string starts with the negativeBefore value: remove it. + // Remember is was there, the number is negative. + if ( negativeBefore && strStartsWith(input, negativeBefore) ) { + input = input.replace(negativeBefore, ''); + inputIsNegative = true; + } + + // Repeat the same procedure for the prefix. + if ( prefix && strStartsWith(input, prefix) ) { + input = input.replace(prefix, ''); + } + + // And again for negative. + if ( negative && strStartsWith(input, negative) ) { + input = input.replace(negative, ''); + inputIsNegative = true; + } + + // Remove the suffix. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice + if ( suffix && strEndsWith(input, suffix) ) { + input = input.slice(0, -1 * suffix.length); + } + + // Remove the thousand grouping. + if ( thousand ) { + input = input.split(thousand).join(''); + } + + // Set the decimal separator back to period. + if ( mark ) { + input = input.replace(mark, '.'); + } + + // Prepend the negative symbol. + if ( inputIsNegative ) { + output += '-'; + } + + // Add the number + output += input; + + // Trim all non-numeric characters (allow '.' and '-'); + output = output.replace(/[^0-9\.\-.]/g, ''); + + // The value contains no parse-able number. + if ( output === '' ) { + return false; + } + + // Covert to number. + output = Number(output); + + // Run the user-specified post-decoder. + if ( decoder ) { + output = decoder(output); + } + + // Check is the output is valid, otherwise: return false. + if ( !isValidNumber(output) ) { + return false; + } + + return output; + } + + +// Framework + + // Validate formatting options + function validate ( inputOptions ) { + + var i, optionName, optionValue, + filteredOptions = {}; + + if ( inputOptions['suffix'] === undefined ) { + inputOptions['suffix'] = inputOptions['postfix']; + } + + for ( i = 0; i < FormatOptions.length; i+=1 ) { + + optionName = FormatOptions[i]; + optionValue = inputOptions[optionName]; + + if ( optionValue === undefined ) { + + // Only default if negativeBefore isn't set. + if ( optionName === 'negative' && !filteredOptions.negativeBefore ) { + filteredOptions[optionName] = '-'; + // Don't set a default for mark when 'thousand' is set. + } else if ( optionName === 'mark' && filteredOptions.thousand !== '.' ) { + filteredOptions[optionName] = '.'; + } else { + filteredOptions[optionName] = false; + } + + // Floating points in JS are stable up to 7 decimals. + } else if ( optionName === 'decimals' ) { + if ( optionValue >= 0 && optionValue < 8 ) { + filteredOptions[optionName] = optionValue; + } else { + throw new Error(optionName); + } + + // These options, when provided, must be functions. + } else if ( optionName === 'encoder' || optionName === 'decoder' || optionName === 'edit' || optionName === 'undo' ) { + if ( typeof optionValue === 'function' ) { + filteredOptions[optionName] = optionValue; + } else { + throw new Error(optionName); + } + + // Other options are strings. + } else { + + if ( typeof optionValue === 'string' ) { + filteredOptions[optionName] = optionValue; + } else { + throw new Error(optionName); + } + } + } + + // Some values can't be extracted from a + // string if certain combinations are present. + throwEqualError(filteredOptions, 'mark', 'thousand'); + throwEqualError(filteredOptions, 'prefix', 'negative'); + throwEqualError(filteredOptions, 'prefix', 'negativeBefore'); + + return filteredOptions; + } + + // Pass all options as function arguments + function passAll ( options, method, input ) { + var i, args = []; + + // Add all options in order of FormatOptions + for ( i = 0; i < FormatOptions.length; i+=1 ) { + args.push(options[FormatOptions[i]]); + } + + // Append the input, then call the method, presenting all + // options as arguments. + args.push(input); + return method.apply('', args); + } + + function wNumb ( options ) { + + if ( !(this instanceof wNumb) ) { + return new wNumb ( options ); + } + + if ( typeof options !== "object" ) { + return; + } + + options = validate(options); + + // Call 'formatTo' with proper arguments. + this.to = function ( input ) { + return passAll(options, formatTo, input); + }; + + // Call 'formatFrom' with proper arguments. + this.from = function ( input ) { + return passAll(options, formatFrom, input); + }; + } + + return wNumb; + +})); diff --git a/osdCamicroscope.php b/osdCamicroscope.php index 86df0f729..aa7837851 100644 --- a/osdCamicroscope.php +++ b/osdCamicroscope.php @@ -1,178 +1,148 @@ - - - - - - - - - [caMicroscope OSD][Subject: <?php echo json_encode($_GET['tissueId']); ?>][User: <?php echo $_SESSION["name"]; ?>] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      - -
      -
      -
      -
      - -
      -
      -
      - + + $default_db_name="quip"; - + + + + + + + + +
      + +
      + + +
      +
      +
      + +
      +
      +
      + + +
      + + + + + } + - - - + + + + + + + + + diff --git a/osdCamicroscope_Lymph.php b/osdCamicroscope_Lymph.php index f66bbaa66..f229cb15b 100644 --- a/osdCamicroscope_Lymph.php +++ b/osdCamicroscope_Lymph.php @@ -1,255 +1,312 @@ + + + + + + + + + + + + +
      + + + + + + + - - - - - - + diff --git a/osdCamicroscope_sc.php b/osdCamicroscope_sc.php index 06868c2aa..058bab55c 100644 --- a/osdCamicroscope_sc.php +++ b/osdCamicroscope_sc.php @@ -1,238 +1,178 @@ - - - - - - - - [caMicroscope OSD][Subject: <?php echo json_encode($_GET['tissueId']); ?>][User: <?php echo $_SESSION["name"]; ?>] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      -
      -
      -
      -
      -
      -
      -
      -
      - -
      - - - - + + + + + + + + +
      +
      +
      +
      +
      +
      +
      +
      +
      + +
      + + + + - - - - - + diff --git a/package.json b/package.json new file mode 100644 index 000000000..338d3d4d0 --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "camic_test", + "version": "1.0.0", + "description": "", + "main": "test/test_server.js", + "scripts": { + "test": "mocha test/functional_tests.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "atob": "^2.1.0", + "btoa": "^1.2.1", + "chai": "^4.1.2", + "express": "^4.16.2", + "lodash": "^4.17.10", + "mocha": "^5.1.1", + "php-express": "0.0.3", + "puppeteer": "^0.9.0" + } +} diff --git a/shared/ToolBar.js b/shared/ToolBar.js new file mode 100644 index 000000000..6d310ebc2 --- /dev/null +++ b/shared/ToolBar.js @@ -0,0 +1,395 @@ +/** + * Get option values for "tool" element, else set default values. + * + * @param element + * @param options + * @constructor + */ +var ToolBar = function (element, options) { + // console.log(options) + this.annotools = options.annotool; + // console.log(this.annotools) + this.FilterTools = options.FilterTools; + this.source = element; // The Tool Source Element + this.top = options.top || '0px'; + this.left = options.left || '150px'; // The Tool Location + this.height = options.height || '30px'; + this.width = options.width || '270px'; + this.zindex = options.zindex || '100'; // To Make Sure The Tool Appears in the Front + this.iid = options.iid || null; + this.cancerType = options.cancerType; + this.imageStatus = options.imageStatus; + this.assignTo = options.assignTo; + this.userType = options.userType; + this.user_email = options.user_email; + this.displayId = options.displayId; + this.annotationActive = isAnnotationActive(); + this.viewer = options.viewer; + + //this.superuser = false; +}; + +/** + * Print message to console. + * @param msg + */ +ToolBar.prototype.showMessage = function (msg) { + console.log(msg) +}; + +ToolBar.prototype.algorithmSelector = function () { + var self = this; + var ftree; + xxx = [] +}; + + +var available_colors = ['#a6cee3', '#1f78b4', '#b2df8a', '#33a02c', '#fb9a99', '#e31a1c', '#fdbf6f', '#ff7f00', '#cab2d6', '#6a3d9a', '#ffff99', '#b15928']; + +var algorithm_color = {}; + +function goodalgo(data, status) { + // console.log(data) + + /* + var blob = []; + for (i = 0; i < data.length; i++) { + var n = {}; + + data[i].title = data[i].provenance.analysis_execution_id; + + n.title = "
      " + data[i].title; + n.key = i.toString(); + n.refKey = data[i].provenance.analysis_execution_id; + n.color = available_colors[i % available_colors.length]; + //algorithm_color[data[i].provenance.analysis_execution_id] = available_colors[i%7] + algorithm_color[data[i].provenance.analysis_execution_id] = available_colors[i % available_colors.length]; + blob.push(n) + } + */ + + max_ver = 0; + for (i = 0; i < data.length; i++) { + var n = {}; + data[i].title = data[i].provenance.analysis_execution_id; + n.title = "
      " + data[i].title; + n.key = i.toString(); + n.refKey = data[i].provenance.analysis_execution_id; + if (n.refKey.includes('lym_v')) { + ver = parseInt(n.refKey.split('lym_v')[1].split('-')[0]); + if (ver > max_ver) { + max_ver = ver + } + } + } + var blob = []; + for (i = 0; i < data.length; i++) { + var n = {}; + //console.log(data[i]) + data[i].title = data[i].provenance.analysis_execution_id; + n.title = "
      " + data[i].title; + n.key = i.toString(); + n.refKey = data[i].provenance.analysis_execution_id; + if (n.refKey == 'lym_v' + max_ver + '-high_res' || n.refKey == 'lym_v' + max_ver + '-low_res' || n.refKey == 'humanmark') { + n.selected = true + } + + //n.color = available_colors[i] + //algorithm_color[data[i].provenance.analysis_execution_id] = available_colors[i] + algorithm_color[data[i].provenance.analysis_execution_id] = available_colors[i % available_colors.length]; + blob.push(n) + } + + ftree = jQuery('#tree').fancytree({ + source: [{ + title: 'Algorithms', key: '1', folder: true, + children: blob, + expanded: true + }], + minExpandLevel: 1, // 1: root node is not collapsible + activeVisible: true, // Make sure, active nodes are visible (expanded). + aria: false, // Enable WAI-ARIA support. + autoActivate: true, // Automatically activate a node when it is focused (using keys). + autoCollapse: false, // Automatically collapse all siblings, when a node is expanded. + autoScroll: false, // Automatically scroll nodes into visible area. + clickFolderMode: 4, // 1:activate, 2:expand, 3:activate and expand, 4:activate (dblclick expands) + checkbox: true, // Show checkboxes. + debugLevel: 2, // 0:quiet, 1:normal, 2:debug + disabled: false, // Disable control + focusOnSelect: false, // Set focus when node is checked by a mouse click + generateIds: false, // Generate id attributes like + idPrefix: 'ft_', // Used to generate node id´s like . + icons: true, // Display node icons. + keyboard: true, // Support keyboard navigation. + keyPathSeparator: '/', // Used by node.getKeyPath() and tree.loadKeyPath(). + quicksearch: false, // Navigate to next node by typing the first letters. + selectMode: 2, // 1:single, 2:multi, 3:multi-hier + tabbable: true, // Whole tree behaves as one single control + titlesTabbable: false, // Node titles can receive keyboard focus + beforeSelect: function (event, data) { + // A node is about to be selected: prevent this for folders: + if (data.node.isFolder()) { + return false + } + }, + select: function (event, data) { + jQuery('#tree').attr('algotree', true); + var node = data.node; + + console.log('!SELECTED NODE : ' + node.title); + targetType = data.targetType; + annotool.getMultiAnnot() + } + }); + + jQuery('#tree').attr('algotree', true); + // Load weight + if (annotool.loadedWeight == false) { + annotool.loadHeatmapWeight(); + annotool.loadedWeight = true; + } + //annotool.getMultiAnnot(); +} + +/* +ToolBar.prototype.toggleAlgorithmSelector = function () { + if (!jQuery('#algosel').attr('eb')) { + jQuery('#algosel').attr('eb', true) + // console.log("initializing...") + jQuery('#algosel').css({ + 'width': '300px', + 'zIndex': 199, + 'visibility': 'hidden' + }) + jQuery('#algosel').on('mousedown', function (e) { + jQuery(this).addClass('draggable').parents().on('mousemove', function (e) { + jQuery('.draggable').offset({ + top: e.pageY - jQuery('.draggable').outerHeight() / 2, + left: e.pageX - jQuery('.draggable').outerWidth() / 2 + }).on('mouseup', function () { + jQuery(this).removeClass('draggable') + }) + }) + e.preventDefault() + }).on('mouseup', function () { + jQuery('.draggable').removeClass('draggable') + }) + } + if (jQuery('#algosel').css('visibility') == 'visible') { + jQuery('#algosel').css({ + 'visibility': 'hidden' + }) + } else { + jQuery('#algosel').css({ + 'visibility': 'visible' + }) + } + this.showMessage('Algorithm Selection Toggled') +} +*/ + +var ALGORITHM_LIST = {}; +var SELECTED_ALGORITHM_LIST = []; +var SELECTED_ALGORITHM_KEYS = []; +var SELECTED_ALGORITHM_COLOR = {}; +var AlgorithmSelectorHidden = true; +//var OVERLAY_MAP = new Map(); +var OVERLAY_LIST = []; + + +/** + * Show/Hide "Select Algorithm" menu + */ +ToolBar.prototype.toggleAlgorithmSelector = function () { + var self = this; + //jQuery("#panel").show("slide"); + var url = 'api/Data/getAlgorithmsForImage.php?iid=' + self.iid; + + //var htmlStr = "

      Select Algorithm

        "; + var htmlStr = "
        Close

        Select Algorithm

          "; + + jQuery.get(url, function (data) { + + d = JSON.parse(data); + + // sorting the algorithms + var tmp_algorithm_list = []; + for (var i = 0; i < d.length; i++) { + tmp_algorithm_list[i] = d[i].provenance.analysis_execution_id; + } + //tmp_algorithm_list = tmp_algorithm_list.sort(); + var algorithms_computer = []; + var algorithms_composite_input = []; + var algorithms_composite_dataset = []; + var algorithms_under = []; + var algorithms_over = []; + + var algorithm_number = tmp_algorithm_list.length; + if (algorithm_number > 0) { + + for (i = 0; i < algorithm_number; i++) { + var index_composite_input = tmp_algorithm_list[i].indexOf("composite_input"); + var index_composite_dataset = tmp_algorithm_list[i].indexOf("composite_dataset"); + var index_under = tmp_algorithm_list[i].indexOf("under_"); + var index_over = tmp_algorithm_list[i].indexOf("over_"); + + if (index_composite_input != -1) { + algorithms_composite_input.push(tmp_algorithm_list[i]); + } else if (index_composite_dataset != -1) { + algorithms_composite_dataset.push(tmp_algorithm_list[i]); + } else if (index_under != -1) { + algorithms_under.push(tmp_algorithm_list[i]); + } else if (index_over != -1) { + algorithms_over.push(tmp_algorithm_list[i]); + } else { + algorithms_computer.push(tmp_algorithm_list[i]); + } + } + algorithms_computer = algorithms_computer.sort(); + algorithms_under = algorithms_under.sort(); + algorithms_over = algorithms_over.sort(); + algorithms_composite_input = algorithms_composite_input.sort(); + algorithms_composite_dataset = algorithms_composite_dataset.sort(); + tmp_algorithm_list = algorithms_computer.concat(algorithms_under, algorithms_over, algorithms_composite_input, algorithms_composite_dataset); + } + + ALGORITHM_LIST = d; + for (var i = 0; i < tmp_algorithm_list.length; i++) { + algorithm_color[tmp_algorithm_list[i]] = available_colors[i % available_colors.length]; + SELECTED_ALGORITHM_COLOR[tmp_algorithm_list[i]] = available_colors[i % available_colors.length]; + + /* + NOTE: 8080 and folder html2 were removed + //user view composite dataset only + if (window.location.port == "8080") { + var index_composite_input1 = tmp_algorithm_list[i].indexOf("composite_input"); + var index_composite_dataset1 = tmp_algorithm_list[i].indexOf("composite_dataset"); + var this_entry = ""; + if (index_composite_input1 != -1) { + this_entry = "human_markup_composite_input"; + } else if (index_composite_dataset1 != -1) { + this_entry = "human_markup_composite_dataset"; + } else + this_entry = ""; + if (this_entry != "") { + htmlStr += "
        • " + this_entry + "
        • "; + } + } else {*/ + htmlStr += "
        • " + tmp_algorithm_list[i] + + "
        • "; + //} + + } + + htmlStr += "

        "; + + jQuery("#panel").html(htmlStr); + + var algorithms_urlparam = JSON.stringify(tmp_algorithm_list); + algorithms_urlparam = algorithms_urlparam.replace("[", "%5B"); + algorithms_urlparam = algorithms_urlparam.replace("]", "%5D"); + algorithms_urlparam = algorithms_urlparam.replace(/"/g, "%22"); + + var tileOverlays = new overlays(self.iid, self.viewer); + OVERLAY_LIST = tileOverlays.getList(algorithms_urlparam); + + /** + * Populate keys array + */ + jQuery("#algorithmList input[type=checkbox]").each(function () { + + var elem = jQuery(this); + var id = (this).value * 1; + for (var i = 0; i < SELECTED_ALGORITHM_KEYS.length; i++) { + if (SELECTED_ALGORITHM_KEYS[i] == (id)) { + + elem.prop('checked', true); + } + } + + }); + self.annotools.getMultiAnnot(); + + /** + * Handler for checkbox .change() + */ + jQuery('#algorithmList input[type=checkbox]').change(function () { + + // Re-populate 'keys' and 'list' arrays + SELECTED_ALGORITHM_LIST = []; + SELECTED_ALGORITHM_KEYS = []; + jQuery("#algorithmList input:checked").each(function () { + + var key = (this).value * 1; // string to number + var value = tmp_algorithm_list[key]; + + SELECTED_ALGORITHM_KEYS.push(key); + SELECTED_ALGORITHM_LIST.push(value); + + }); + + // Show segmentation + // Display Tiles + tileOverlays.toggle(OVERLAY_LIST, SELECTED_ALGORITHM_LIST); + // Draw segmentation + self.annotools.getMultiAnnot(); + + }); + + /* + jQuery("#submitAlgorithms").click(function(){ + var selected= []; + SELECTED_ALGORITHM_LIST = []; + jQuery("#algorithmList input:checked").each(function() { + SELECTED_ALGORITHM_LIST.push(ALGORITHM_LIST[(this).value * 1].analysis.execution_id); + SELECTED_ALGORITHM_KEYS.push((this).value*1); + }); + + self.annotools.getMultiAnnot(); + jQuery("#panel").html(""); + jQuery("#panel").hide("slide"); + }); + */ + + jQuery("#cancelAlgorithms").click(function () { + jQuery("#panel").html(""); + jQuery("#panel").hide("slide"); + AlgorithmSelectorHidden = true; + }); + + jQuery("#closeFilterPanel").click(function () { + jQuery("#panel").html(""); + jQuery("#panel").hide("slide"); + AlgorithmSelectorHidden = true; + }); + + }); + + if (AlgorithmSelectorHidden == true) { + jQuery("#panel").show("slide"); + AlgorithmSelectorHidden = false; + } else { + jQuery("#panel").html(""); + jQuery("#panel").hide("slide"); + + AlgorithmSelectorHidden = true; + } + +}; + +ToolBar.prototype.setNormalMode = function () { + this.annotools.mode = 'normal'; + + jQuery("canvas").css("cursor", "default"); + jQuery("#drawRectangleButton").removeClass('active'); + jQuery("#drawFreelineButton").removeClass('active'); + jQuery("#drawDotButton").removeClass("active"); // Dot Tool + jQuery("#mergeStep2Button").removeClass("active"); // merge Step2 Button + jQuery("#freeLineMarkupButton").removeClass("active"); + jQuery("#markuppanel").hide(); + jQuery("#qualitymarkuppanel").hide(); + jQuery("#switchuserpanel").hide(); + + this.annotools.drawLayer.hide(); + this.annotools.addMouseEvents() +}; diff --git a/shared/buttons-bak.js b/shared/buttons-bak.js new file mode 100644 index 000000000..faafe344d --- /dev/null +++ b/shared/buttons-bak.js @@ -0,0 +1,277 @@ +//ToolBar.prototype.createButtons = function () { + + /* BOOKMARK */ + this.bookmarkButton = jQuery('', { + title: 'Bookmark/Share current state', + class: 'toolButton', + src: 'images/ic_insert_link_white_24dp_1x.png' + }); + tool.append(this.bookmarkButton); + + this.bookmarkButton.on('click', function () { + console.log('bookmark'); + + // Get ViewPort + var bounds = viewer.viewport.getBounds(); + console.log(bounds); + + // Get Filters + var filters = []; + jQuery('#selected li').each(function () { + var id = this.id; + var filter = hashTable[id]; + // filters.push(filter.generatedFilter.getFilter()) + var f = {}; + var filterName = filter.name; + var filterVal = filter.generatedFilter.getParams(); + f.name = filterName; + f.value = filterVal; + filters.push(f) + // sync &= filter.generatedFilter.sync + }); + console.log(filters); + + var state = { + 'state': { + 'filters': filters, + 'viewport': bounds, + 'pan': viewer.viewport.getCenter(), + 'zoom': viewer.viewport.getZoom(), + 'tissueId': this.annotools.iid + } + }; + console.log(state); + + // var bookmarkURLDiv = jQuery.create('
        ').addClass('bookmarkURLDiv') + var bookmarkURLDiv = jQuery('#bookmarkURLDiv'); + bookmarkURLDiv.html(''); + var input = jQuery(''); + var submit = jQuery('